如何在Jetpack Compose中实现物体在两条路径间的平滑运动切换?
解决Jetpack Compose中旋转轨道平滑切换的问题
核心问题分析
原代码通过布尔值直接切换半径,导致半径瞬间突变,出现跳变和卡顿。要实现沿切线平滑过渡,需要让半径从当前值连续动画过渡到目标值,同时保持角度的持续旋转,这样运动轨迹就是自然的螺旋切线路径。
修改后的完整代码
@Composable fun AnimateObject() { // 无限旋转的角度动画,持续运行不中断 val transition = rememberInfiniteTransition() val animatedProgress = transition.animateFloat( initialValue = 0f, targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween(durationMillis = 3000, easing = LinearEasing), repeatMode = RepeatMode.Restart ) ) val outerCircleRadius = 450f val innerCircleRadius = 250f // 使用Animatable管理当前半径,支持平滑过渡 val currentRadius = remember { Animatable(outerCircleRadius) } var isInOuterCircle by remember { mutableStateOf(true) } val angle = animatedProgress.value * 360f val radians = Math.toRadians(angle.toDouble()) Canvas(modifier = Modifier.size(200.dp), onDraw = { val canvasCenter = Offset(size.width / 2, size.height / 2) // 绘制内外轨道 drawCircle( color = Color.Gray.copy(alpha = 0.3f), center = canvasCenter, radius = outerCircleRadius, style = Stroke(width = 2.dp.toPx()) ) drawCircle( color = Color.Gray.copy(alpha = 0.3f), center = canvasCenter, radius = innerCircleRadius, style = Stroke(width = 2.dp.toPx()) ) // 计算当前位置:角度持续旋转 + 半径平滑过渡 val x = canvasCenter.x + currentRadius.value * cos(radians).toFloat() val y = canvasCenter.y + currentRadius.value * sin(radians).toFloat() // 绘制运动的形状 drawCircle( color = Color.Blue, center = Offset(x, y), radius = 16.dp.toPx() ) }) Row { Button( onClick = { isInOuterCircle = !isInOuterCircle // 启动半径的平滑过渡动画 coroutineScope.launch { currentRadius.animateTo( targetValue = if (isInOuterCircle) outerCircleRadius else innerCircleRadius, animationSpec = tween(durationMillis = 500, easing = LinearOutSlowInEasing) ) } }, modifier = Modifier.size(width = 150.dp, height = 50.dp) ) { Text(text = if (isInOuterCircle) "切换到内圈" else "切换到外圈") } } }
关键优化点
- 用
Animatable管理半径:替代直接切换布尔值,点击按钮时启动半径的过渡动画,让半径从当前值平滑变化到目标值 - 保持角度动画不中断:无限旋转的角度动画持续运行,不会因为切换半径而停顿
- 移除冗余的状态变量:
playerXOffset和playerYOffset不需要单独存状态,直接在Canvas中通过当前半径和角度计算即可,减少不必要的重组 - 选择合适的缓动函数:使用
LinearOutSlowInEasing让过渡更自然,也可以根据需求调整动画时长
效果说明
修改后,点击按钮时蓝色形状会沿着当前运动的切线方向,以螺旋轨迹平滑过渡到目标轨道,全程保持运动状态,不会出现跳变和卡顿。
内容的提问来源于stack exchange,提问作者Dev
相关产品推荐
相关产品推荐

