为何animateTo函数无法改变animatedWidth变量值?
问题分析与修复方案
核心问题
动画失效的根源在于:
LaunchedEffect(Unit)在Composable初始化阶段就执行,此时canvasSize仍是初始的Size.Zero,计算出的targetWidth为0,动画从0到0自然无变化。- Canvas的实际尺寸是在绘制阶段才赋值给
canvasSize的,此时初始的LaunchedEffect已经执行完毕,不会重新触发动画逻辑。
修复后的完整代码
@Composable fun OutlinedLinearProgressBar() { val animatedWidth = remember { Animatable(0f) } var canvasSize by remember { mutableStateOf(Size.Zero) } // 当Canvas尺寸确定后启动动画 LaunchedEffect(canvasSize) { // 跳过尺寸未初始化的情况 if (canvasSize.width == 0f) return@LaunchedEffect val targetWidth = canvasSize.width / 2.18f val duration = 1000 animatedWidth.animateTo( targetValue = targetWidth, animationSpec = tween(durationMillis = duration), ) } Box(modifier = Modifier.fillMaxSize()) { Canvas(modifier = Modifier.fillMaxSize()) { // 仅在尺寸变化时更新canvasSize,避免不必要的重组 if (size != canvasSize) { canvasSize = size } drawRect(color = Color.Black, size = size) val centerY = center.y drawRect( style = Stroke(width = 10f), color = Color.White, topLeft = Offset(x = size.width / 4f, y = centerY - (size.height / 10f) / 2f), size = Size( width = size.width / 2f, height = size.height / 10f, ), ) drawRect( color = Color.Green, style = Fill, topLeft = Offset(x = size.width / 3.7f, y = centerY - (size.height / 10f) / 2.5f), size = Size( width = animatedWidth.value, height = size.height / 12.5f, ), ) } } }
关键修改点
- 调整动画触发时机:将
LaunchedEffect的触发key改为canvasSize,确保只有当Canvas完成测量、尺寸有效时才启动动画。 - 优化状态更新逻辑:在Canvas绘制块中,仅当当前尺寸与
canvasSize不一致时才更新状态,避免频繁重组。 - 移除冗余代码:删掉未使用的
animationPlayed变量,简化代码结构。 - 添加边界判断:在动画逻辑中跳过尺寸未初始化的情况,避免无效计算。
修改后,点击按钮显示Composable时,Canvas会先完成尺寸测量,随后触发动画,绿色矩形就能从0开始正常沿长度方向增长。
内容的提问来源于stack exchange,提问作者Deusnominus
相关产品推荐
相关产品推荐

