AnimatedVisibility结合weight属性无动画效果的问题排查与解决
AnimatedVisibility 搭配 weight 无动画的问题分析与解决
问题原因
weight 是 Column 在测量阶段就会计算的布局参数,当中间的 AnimatedVisibility 切换可见性时,Column 会直接重新分配剩余空间给上下两个 Box——这个测量层面的尺寸突变,没办法被 AnimatedVisibility 的动画系统捕捉到,自然就不会有平滑过渡效果。而用固定高度时,组件的尺寸变化是明确的、可被动画系统追踪的,所以动画能正常运行。
解决方法
放弃直接用 weight,改用动画状态来动态计算三个 Box 的高度,让尺寸变化处于动画系统的可控范围内。具体步骤:
- 计算 Column 的可用高度(总高度减去按钮的固定高度)
- 用
animateDpAsState根据visible状态,动态生成上下 Box 和中间 Box 的目标高度 - 把
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
相关产品推荐
相关产品推荐

