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

为何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,
                ),
            )
        }
    }
}

关键修改点

  1. 调整动画触发时机:将LaunchedEffect的触发key改为canvasSize,确保只有当Canvas完成测量、尺寸有效时才启动动画。
  2. 优化状态更新逻辑:在Canvas绘制块中,仅当当前尺寸与canvasSize不一致时才更新状态,避免频繁重组。
  3. 移除冗余代码:删掉未使用的animationPlayed变量,简化代码结构。
  4. 添加边界判断:在动画逻辑中跳过尺寸未初始化的情况,避免无效计算。

修改后,点击按钮显示Composable时,Canvas会先完成尺寸测量,随后触发动画,绿色矩形就能从0开始正常沿长度方向增长。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 07:13:09