如何使用animateContentSize实现Box在fillMaxSize与0间的尺寸动画?
问题解决:Compose中Box从fillMaxSize缩回到0的动画失效
问题原因
你当前使用的 animateContentSize() 是专门用于组件自身内容尺寸变化的动画API,但你是通过 fillMaxSize(ratio) 基于父容器比例修改Box尺寸,这种依赖父容器的尺寸变更无法被 animateContentSize() 正确捕捉,导致缩小动画失效。同时当 fillMaxSize(0f) 时,Box尺寸变为0,动画系统无法追踪从有尺寸到0的过渡过程。
解决方案一:使用animateFloatAsState驱动比例动画
通过 animateFloatAsState 控制 fillMaxSize() 的比例参数,直接驱动尺寸变化的动画,双向过渡都会生效:
修改TopBar中蓝色Box的代码:
@Composable fun TopBar(){ var tabSelected by remember { mutableStateOf(false) } // 用animateFloatAsState创建比例动画 val sizeRatio by animateFloatAsState( targetValue = if(tabSelected) 1f else 0f, animationSpec = tween(durationMillis = 300) // 可自定义动画时长 ) Row( modifier = Modifier .fillMaxWidth() .height(IntrinsicSize.Min) .border(1.dp, Color.Black) .padding(start = 8.dp, end = 8.dp, top = 7.dp, bottom = 7.dp) ){ // 其他组件保持不变... Box( modifier = Modifier .weight(0.25f) .fillMaxHeight(), contentAlignment = Alignment.Center ){ Box( modifier = Modifier .clip(shape = RoundedCornerShape(8.dp)) .fillMaxSize(sizeRatio) // 使用动画化的比例值 .background(Color.Blue) .clickable( interactionSource = remember { MutableInteractionSource() }, indication = null ) { tabSelected = !tabSelected } ) Text(text = "1") } // 其他组件保持不变... } }
解决方案二:用内容驱动animateContentSize动画
让Box的尺寸由内部内容撑开,这样 animateContentSize() 就能正确捕捉尺寸变化,实现双向动画:
修改蓝色Box部分代码:
Box( modifier = Modifier .weight(0.25f) .fillMaxHeight(), contentAlignment = Alignment.Center ){ Box( modifier = Modifier .clip(shape = RoundedCornerShape(8.dp)) .animateContentSize() .background(Color.Blue) .clickable( interactionSource = remember { MutableInteractionSource() }, indication = null ) { tabSelected = !tabSelected } ) { // 选中时用Spacer撑满整个父容器空间 if(tabSelected) { Spacer(modifier = Modifier.fillMaxSize()) } } Text(text = "1") }
说明
两种方案都能解决你的问题:
- 方案一更适合需要精确控制尺寸比例的场景,动画过渡更直接。
- 方案二更贴合
animateContentSize()的设计初衷,通过内容变化触发动画。
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

