可以用Jetpack Compose制作像gif这样的动画吗?

enter image description here

推荐答案

其中一种方法是使用可相互设置比例和Alpha动画的动画对象.

enter image description here

创建包含2个动画对象的类

class AnimatedCountdownTimer(
    private val coroutineScope: CoroutineScope
) {

    private val animatableScale = Animatable(1f)
    private val animatableAlpha = Animatable(1f)

    val scale: Float
        get() = animatableScale.value

    val alpha: Float
        get() = animatableAlpha.value

    fun start(initialValue: Int, endValue: Int, onChange: (Int) -> Unit) {

        var value = initialValue

        coroutineScope.launch {
            while (value > endValue - 1) {
                onChange(value)
                animatableScale.snapTo(1f)
                animatableAlpha.snapTo(1f)
                animatableScale.animateTo(2f, animationSpec = tween(750))
                animatableAlpha.animateTo(0f, animationSpec = tween(250))
                value--

            }
        }
    }
}

并将其用作

@Preview
@Composable
fun TimerTest() {


    var timer by remember {
        mutableStateOf(5)
    }

    val coroutineScope = rememberCoroutineScope()

    val animatedCountdownTimer = remember {
        AnimatedCountdownTimer(coroutineScope)
    }

    Column(
        modifier = Modifier.fillMaxSize().padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            modifier = Modifier.graphicsLayer {
                scaleX = animatedCountdownTimer.scale
                scaleY = animatedCountdownTimer.scale
                alpha = animatedCountdownTimer.alpha
            },
            text = "$timer",
            fontSize = 120.sp,
            fontWeight = FontWeight.Bold,
            color = Color.Gray
        )
        Spacer(Modifier.height(20.dp))
        Button(
            modifier = Modifier.fillMaxWidth(),
            onClick = {
                animatedCountdownTimer.start(5, 0) {
                    timer = it
                }
            }
        ) {
            Text("Start")
        }
    }
}

如果你不想在动画结束后zoom 到1f,那么只需要添加if块,这样它就可以保持在比例上.任何参数都可以很容易地自定义持续时间或最大规模.

如果你想保持最后一个数字的比例,你可以这样使用它

  coroutineScope.launch {
        while (value > endValue - 1) {
            onChange(value)
            animatableScale.snapTo(1f)
            animatableAlpha.snapTo(1f)
            animatableScale.animateTo(2f, animationSpec = tween(750))
            if (value > endValue) {
                animatableAlpha.animateTo(0f, animationSpec = tween(250))
            }
            value--
        }
    }

Android相关问答推荐

广播接收者意图从服务内设置,而不被其他服务接收

将Android Studio插件复制到离线网络

Android 14(Oneui 6)中的本地推送通知行为不一致

如何在Jetpack导航中不显示目的地?

我如何剪裁一个可由另一个合成的

格雷德的两个星号是什么意思?非路径

如何阻止Gradle在编译时生成app-metadata.properties

Android Compose Pages 3-一次加载所有页面,无需在LazyColumn中滚动,无需网络调用和内部滚动

无法将非静态方法与Frida挂钩

Jetpack Compose:带芯片的Textfield

不能有意地从一个活动的可组合功能转移到另一个活动

解决失败:Landroidx/compose/runtime/PrimitiveSnapshotStateKt

是否可以在 compose 中使用三次贝塞尔曲线进行动画?

[Android][Room] 将密封类存储到 Room 数据库中

Electric Eel 后 Gradle 项目同步失败 | 2022.1.1更新

Int 传递给 Intent 但Android工作室说我传递了一个字符串

如何在行/列/卡片 compose 中添加左边框

重命名列失败的房间自动迁移(NOT NULL 约束失败,生成错误的迁移类)

使用 Jetpack Compose 时,如何以简单的方式在 Color.kt 中定义 colored颜色 ?

如何从构建的流对象中发出值