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

AnimatedVisibility结合weight属性无动画效果的问题排查与解决

AnimatedVisibility 搭配 weight 无动画的问题分析与解决

问题原因

weight 是 Column 在测量阶段就会计算的布局参数,当中间的 AnimatedVisibility 切换可见性时,Column 会直接重新分配剩余空间给上下两个 Box——这个测量层面的尺寸突变,没办法被 AnimatedVisibility 的动画系统捕捉到,自然就不会有平滑过渡效果。而用固定高度时,组件的尺寸变化是明确的、可被动画系统追踪的,所以动画能正常运行。

解决方法

放弃直接用 weight,改用动画状态来动态计算三个 Box 的高度,让尺寸变化处于动画系统的可控范围内。具体步骤:

  1. 计算 Column 的可用高度(总高度减去按钮的固定高度)
  2. 用 animateDpAsState 根据 visible 状态,动态生成上下 Box 和中间 Box 的目标高度
  3. 把 weight 替换成动态计算的 height() 修饰符,同时保留 AnimatedVisibility 的入场/退场动画

修改后的示例代码

@Composable
fun AnimatedVisibilityEx(modifier: Modifier = Modifier) {
    var visible by remember { mutableStateOf(true) }
    // 获取父布局的可用高度(减去按钮的padding和高度)
    val parentHeight = remember { mutableStateOf(0.dp) }
    // 按钮的总高度(自身高度+top padding)
    val buttonTotalHeight = 32.dp + ButtonDefaults.MinHeight
    // 计算可分配给三个Box的高度
    val availableHeight = parentHeight.value - buttonTotalHeight

    // 动态计算各Box的目标高度
    val topBottomHeight by animateDpAsState(
        targetValue = if (visible) availableHeight / 3 else availableHeight / 2,
        animationSpec = tween(durationMillis = 300)
    )
    val middleHeight by animateDpAsState(
        targetValue = if (visible) availableHeight / 3 else 0.dp,
        animationSpec = tween(durationMillis = 300)
    )

    Box(modifier = modifier.fillMaxSize().onSizeChanged {
        parentHeight.value = it.height.toDp()
    }) {
        Column(horizontalAlignment = Alignment.CenterHorizontally) {

            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(topBottomHeight)
                    .background(Color.LightGray)
                    .border(width = 2.dp, color = Color.Blue, shape = CircleShape)
            )

            AnimatedVisibility(
                visible = visible,
                enter = fadeIn() + expandVertically(),
                exit = fadeOut() + shrinkVertically()
            ) {
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(middleHeight)
                        .background(MaterialTheme.colorScheme.primary)
                )
            }

            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(topBottomHeight)
                    .background(Color.LightGray)
                    .border(width = 2.dp, color = Color.Red, shape = CircleShape)
            )

            Button(
                onClick = { visible = !visible },
                modifier = Modifier.padding(top = 32.dp)
            ) {
                Text(text = "Toggle Visible")
            }
        }
    }
}

补充说明

  • 用 onSizeChanged 获取父布局的实际高度,确保动态计算的高度符合屏幕实际空间
  • 可以根据需求调整 animationSpec 来修改动画的速度、曲线
  • AnimatedVisibility 的入场/退场动画可以自定义,比如示例里的淡入淡出+伸缩组合,让中间组件的显示隐藏更自然

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 06:11:27