如何让Jetpack Compose Row中所有元素随组件显隐同步动画位移?
实现iOS风格表格编辑的同步位移动画
问题出在AnimatedVisibility默认仅对自身进行滑入滑出动画,但Row内的其他元素(比如带weight的Text)会因布局空间突变直接跳转,没有过渡效果。要让整个Row的元素同步收缩/展开,需要让布局尺寸变化也参与动画,以下是两种可行方案:
方案一:给Row添加animateContentSize配合尺寸动画
给Row添加animateContentSize修饰符,让Row的宽度变化带动内部元素平滑过渡,同时给AnimatedVisibility添加尺寸动画效果,确保空间变化和滑入滑出同步。
修改后的代码:
Row( modifier = Modifier .fillMaxWidth() .padding(vertical = 10.dp) .animateContentSize(animationSpec = tween(durationMillis = 300)), // 新增:让Row尺寸变化有动画 verticalAlignment = Alignment.CenterVertically ) { Icon(...) Spacer(modifier = Modifier.width(4.dp)) Text(text = keyInfo.name, modifier = Modifier.weight(1.0f), maxLines = 1) Spacer(modifier = Modifier.width(10.dp)) SettingsLabel(text = keyInfo.created.shortPrinted()) AnimatedVisibility( visible = allowSelection, enter = slideInHorizontally(initialOffsetX = { w -> w }) + expandHorizontally(), // 新增:展开尺寸动画 exit = slideOutHorizontally(targetOffsetX = { w -> w }) + shrinkHorizontally() // 新增:收缩尺寸动画 ) { IconButton( onClick = onSelectionClick, modifier = Modifier .padding(start = 16.dp) .size(28.dp) ) { when (isSelected) { true -> Icon( Icons.Outlined.CheckCircle, "${keyInfo.name} selected for edit" ) false -> Icon( Icons.Default.RadioButtonUnchecked, "${keyInfo.name} not selected for edit" ) } } } }
方案二:用AnimatedContent替代AnimatedVisibility
通过AnimatedContent控制选择按钮的显示状态,让整个布局的变化被统一处理,实现元素同步位移。
修改后的代码:
Row( modifier = Modifier .fillMaxWidth() .padding(vertical = 10.dp), verticalAlignment = Alignment.CenterVertically ) { Icon(...) Spacer(modifier = Modifier.width(4.dp)) Text(text = keyInfo.name, modifier = Modifier.weight(1.0f), maxLines = 1) Spacer(modifier = Modifier.width(10.dp)) SettingsLabel(text = keyInfo.created.shortPrinted()) AnimatedContent( targetState = allowSelection, transitionSpec = { // 同步滑入滑出和尺寸变化动画 slideInHorizontally(initialOffsetX = { w -> w }) with slideOutHorizontally(targetOffsetX = { w -> w }) using SizeTransform(clip = false) } ) { isVisible -> if (isVisible) { IconButton( onClick = onSelectionClick, modifier = Modifier .padding(start = 16.dp) .size(28.dp) ) { when (isSelected) { true -> Icon( Icons.Outlined.CheckCircle, "${keyInfo.name} selected for edit" ) false -> Icon( Icons.Default.RadioButtonUnchecked, "${keyInfo.name} not selected for edit" ) } } } else { Spacer(modifier = Modifier.width(0.dp)) // 隐藏时保持布局结构 } } }
注意事项
- 可通过调整
tween的durationMillis参数(建议200-300ms)匹配iOS的动画节奏 - 确保选择按钮的
padding在动画过程中自然过渡,避免出现突兀间隙 - 方案一更简洁,适合简单场景;方案二更灵活,支持复杂状态切换
内容的提问来源于stack exchange,提问作者Travis Griggs
相关产品推荐
相关产品推荐

