Как реализовать анимацию translate + scale в Jetpack Compose?

У меня есть экран с изображением в одном углу экрана, и я хочу анимировать его в центре экрана. Что-то вроде перехода от

      Icon(
    painter = //,
    contentDescription = //,
    modifier = Modifier.size(36.dp)
)

к

      Icon(
    painter = //,
    contentDescription = //,
    modifier = Modifier.fillMaxSize()
)

Первый находится в верхнем левом углу экрана, а второй - в центре. Как я могу перемещаться между двумя состояниями?

2 ответа

Чтобы анимация работала в Compose, вам нужно анимировать значение определенного модификатора. Невозможно использовать анимацию между разными наборами модификаторов.

Следуя этому параграфу документации, вы можете анимировать значение для Modifier.size.

Сначала я жду, пока определится размер изображения, с этим значением size модификатор можно установить (я использую then с пустым Modifier перед этим), а затем это значение можно анимировать.

Вот пример:

      val animatableSize = remember { Animatable(DpSize.Zero, DpSize.VectorConverter) }
val (containerSize, setContainerSize) = remember { mutableStateOf<DpSize?>(null) }
val (imageSize, setImageSize) = remember { mutableStateOf<DpSize?>(null) }
val density = LocalDensity.current
val scope = rememberCoroutineScope()
Button(onClick = {
    scope.launch {
        if (imageSize == null || containerSize == null) return@launch
        val targetSize = if (animatableSize.value == imageSize) containerSize else imageSize
        animatableSize.animateTo(
            targetSize,
            animationSpec = tween(durationMillis = 1000)
        )
    }
}) {
    Text("Animate")
}
Box(
    Modifier
        .padding(20.dp)
        .size(300.dp)
        .fillMaxSize()
        .background(Color.LightGray)
        .onSizeChanged { size ->
            setContainerSize(
                with(density) { size.toSize().toDpSize() }
            )
        }
) {
    Image(
        Icons.Default.PriorityHigh,
        contentDescription = null,
        modifier = Modifier
            .then(
                Modifier.run {
                    if (animatableSize.value != DpSize.Zero) {
                        size(animatableSize.value)
                    } else {
                        this
                    }
                }
            )
            .onSizeChanged { size ->
                if (imageSize != null) return@onSizeChanged
                val dpSize = with(density) { size.toSize().toDpSize() }
                setImageSize(dpSize)
                scope.launch {
                    animatableSize.snapTo(dpSize)
                }
            }
    )
}

Результат:

Что-то простое:

      @Composable
fun DUM_E(){
val modifier = Modifier.animateContentSize()
 Icon(
 modifier =
     if(triggered) modifier.fillMaxSize()
     else modifier.size(36.dp)
 )
}

Если вы хотите также анимировать смещение, просто оставьте комментарий ниже, и я, возможно, изменю ответ.

Другие вопросы по тегам