Jetpack Compose中如何正确测量父视图高度并实现视图动画?
Compose视图测量与动画修复方案
问题根源
你的代码存在循环依赖问题:初始时columnHeightDp为0.dp,你给子Column设置了.height(heightInDp),这会强制视图以0高度布局,导致onGloballyPositioned回调拿到的高度就是0,最终动画始终无法获取到视图的真实高度,出现图中高度为0的异常情况。
修复方案
要先让视图完成一次正常布局,获取到真实高度后再应用高度动画。核心调整点:
- 初始状态不强制设置高度,用
wrapContentHeight()让视图自然测量自身高度; - 仅当
columnHeightDp不为0时,才将动画高度应用到视图上; - 限制高度更新逻辑,避免重复触发不必要的布局刷新。
修改后的代码
@Preview(showBackground = true) @Composable fun MoveText() { val density = LocalDensity.current var columnHeightDp by remember { mutableStateOf(0.dp) } var visible by remember { mutableStateOf(true) } // 动画状态定义 val iconOffsetAnimation: Dp by animateDpAsState( targetValue = if (visible) 13.dp else 0.dp, animationSpec = tween(1000) ) val textOffsetAnimation: Dp by animateDpAsState( targetValue = if (visible) 6.dp else 0.dp, animationSpec = tween(1000) ) val viewAlpha: Float by animateFloatAsState( targetValue = if (visible) 1f else 0f, animationSpec = tween(1000) ) val heightInDp: Dp by animateDpAsState( targetValue = if (visible) columnHeightDp else 0.dp, animationSpec = tween(1000) ) ScrollComposeTheme { Column( modifier = Modifier .fillMaxWidth() .padding(start = 16.dp, top = 16.dp) ) { Column( modifier = Modifier .onGloballyPositioned { coordinates -> // 仅首次获取真实高度时更新,避免重复触发布局 if (columnHeightDp == 0.dp) { with(density) { columnHeightDp = coordinates.size.height.toDp() } } } // 动态切换高度设置:初始自然布局,获取高度后应用动画 .run { if (columnHeightDp != 0.dp) height(heightInDp) else wrapContentHeight() } .background(Color.LightGray) ) { Image( modifier = Modifier.padding(top = iconOffsetAnimation), alpha = viewAlpha, imageVector = Icons.Default.ShoppingCart, contentDescription = null, ) Text( modifier = Modifier.padding(top = textOffsetAnimation), text = "Hello, Anna", fontSize = 20.sp, color = Color.Black.copy(alpha = viewAlpha), ) } Button( modifier = Modifier.padding(top = 10.dp), onClick = { visible = !visible } ) { Text(text = "Move Text") } } } }
关键修改说明
- 在
onGloballyPositioned中增加判断,仅在columnHeightDp为0时更新高度,避免视图布局变化时重复触发更新; - 使用
Modifier.run动态切换高度设置:初始阶段用wrapContentHeight()让视图正常测量自身高度,获取到真实高度后再应用动画高度; - 这样就能保证第一次布局时拿到视图的真实高度,后续动画可以基于这个高度展开,实现预期的收起/展开效果。
内容的提问来源于stack exchange,提问作者Compose Learner
相关产品推荐
相关产品推荐

