You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose平滑启停旋转动画:解决停止跳变问题

解决方案

要实现停止时保留当前角度、下次启动从该角度继续的平滑旋转动画,不要用InfiniteTransition(它无法暂停并保留状态),改用Animatable手动控制动画生命周期,结合协程实现无限旋转,具体实现如下:

核心思路

  • 用Animatable存储当前旋转角度,它能自动保留当前值,支持暂停/继续操作
  • 用remember保存上次停止时的角度,确保重启动画时从该位置启动
  • 通过LaunchedEffect监听isFetchingNewRates状态,动态启动或取消旋转协程

完整代码实现

@Composable
fun RatesStatus(
    ratesStatus: RateStatus,
    onRateRefreshClicked: () -> Unit,
    isFetchingNewRates: Boolean = false
) {
    // 保存上次停止时的旋转角度
    var lastRotation by remember { mutableStateOf(0f) }
    // 初始化Animatable,初始值为上次停止的角度
    val rotation = remember { Animatable(lastRotation) }

    LaunchedEffect(isFetchingNewRates) {
        if (isFetchingNewRates) {
            // 启动时快速定位到上次停止的角度
            rotation.snapTo(lastRotation)
            // 无限循环旋转:每次累加360度,线性动画持续2秒
            while (true) {
                rotation.animateTo(
                    targetValue = rotation.value - 360f,
                    animationSpec = tween(durationMillis = 2000, easing = LinearEasing)
                )
            }
        } else {
            // 停止动画时,保存当前角度到lastRotation
            lastRotation = rotation.value
            // 取消当前动画协程
            rotation.stop()
        }
    }

    Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.SpaceBetween
    ) {
        Row {
            Image(
                modifier = Modifier.size(50.dp),
                painter = painterResource(Res.drawable.exchange_illustration),
                contentDescription = "Exchange rate illustration"
            )

            Spacer(modifier = Modifier.width(12.dp))

            Column {
                Text(
                    text = displayCurrentDateTime(),
                    color = Color.White
                )
                Text(
                    text = stringResource(ratesStatus.title),
                    color = ratesStatus.color,
                    fontSize = MaterialTheme.typography.bodySmall.fontSize
                )
            }
        }

        IconButton(
            onClick = onRateRefreshClicked
        ) {
            Icon(
                modifier = Modifier
                    .size(24.dp)
                    .graphicsLayer {
                        // 直接使用Animatable的当前值作为旋转角度
                        rotationZ = rotation.value
                    },
                painter = painterResource(Res.drawable.refresh_ic),
                contentDescription = stringResource(Res.string.start_refresh),
                tint = staleColor
            )
        }
    }
}

关键细节说明

  1. Animatable状态保留:Animatable内部维护当前动画值,停止时不会自动重置,彻底解决停止时跳转初始角度的问题
  2. lastRotation的作用:组件重组时,Animatable会重新初始化,lastRotation确保重启动画时从上次停止的位置继续
  3. 协程循环控制:while(true)配合animateTo实现无限旋转,每次旋转完成后自动累加角度,保证动画连续性
  4. 平滑启停:启动时用snapTo快速定位到上次停止角度,无跳转;停止时直接保存当前值,动画自然终止

内容的提问来源于stack exchange,提问作者ant2009

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 11:14:52