如何在Jetpack Compose中实现一个平移和缩放动画?

3

我有一个屏幕,在屏幕的一个角落有一张图片,我想把它动画到屏幕中心。就像从角落到中心移动一样。

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

to

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

第一个在屏幕左上角,第二个在中心。我该如何在这两种状态之间进行动画变换?


1
如果要占据整个屏幕宽度,你只需要动画化图标的大小。它会自动居中。 - Richard Onslow Roper
2个回答

7
为使Compose中的动画工作,您需要对某个特定修饰符的值进行动画处理。您无法在不同的修饰符集之间进行动画处理。
根据文档段落,您可以为Modifier.size的值设置动画效果。
首先,我等待图像的大小确定,使用空的Modifierthen函数设置size修饰符的值,然后对该值进行动画处理。
下面是一个示例:
Column {
    val animatableSize = remember { Animatable(Size.Zero, Size.VectorConverter) }
    val (containerSize, setContainerSize) = remember { mutableStateOf<Size?>(null) }
    val (imageSize, setImageSize) = remember { mutableStateOf<Size?>(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)
            .background(Color.LightGray)
            .onSizeChanged { size ->
                setContainerSize(size.toSize())
            }
    ) {
        Image(
            Icons.Default.Person,
            contentDescription = null,
            modifier = Modifier
                .then(
                    if (animatableSize.value != Size.Zero) {
                        animatableSize.value.run {
                            Modifier.size(
                                width = with(density) { width.toDp() },
                                height = with(density) { height.toDp() },
                            )
                        }
                    } else {
                        Modifier
                    }
                )
                .onSizeChanged { intSize ->
                    if (imageSize != null) return@onSizeChanged
                    val size = intSize.toSize()
                    setImageSize(size)
                    scope.launch {
                        animatableSize.snapTo(size)
                    }
                }
        )
    }
}

结果:


谢谢你的回答。你能否请提一下DpSize类需要哪些依赖项?我无法导入它。 - Arpit Shukla
@ArpitShukla 我的错。DpSize 是在 Compose 1.1.0-beta 中引入的,请查看已更新的答案,不包括它。 - Phil Dukhov

7

试一下这个:

@Composable
fun DUM_E_MARK_II(triggered: Boolean) {
    BoxWithConstraints {
        val size by animateDpAsState(if (triggered) 36.dp else maxHeight)
        Icon(
            imageVector = Icons.Filled.Warning,
            contentDescription = "Just a better solution to the problem",
            modifier = Modifier.size(size)
        )
    }
}

这个gif有点卡顿,但那是录制时的错误。实际动画非常流畅。 - Richard Onslow Roper
3
那么,是什么让你觉得这不是正确的解决方案?与标记答案相比,它更有效。 - Richard Onslow Roper
这是更简单的解决方案。谢谢! - Tgo1014
1
如果有人需要屏幕的最大高度作为 maxHeight 参数,可以在组合范围内调用 LocalConfiguration.current.screenHeightDp 来获取它,这可能会有所帮助。 - user17356317

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接