如何在Jetpack Compose中实现0至wrap_content的宽度动画?
解决Jetpack Compose滑动显示组件到wrap_content宽度的问题
要实现滑动后卡片宽度动画过渡到wrap_content尺寸,核心是获取目标组件(比如删除按钮)的实际渲染宽度,而非使用固定值。可以通过Modifier.onSizeChanged捕获组件的真实尺寸,再将其作为动画的目标值。
具体实现步骤
- 存储目标宽度状态:用
remember保存目标组件的实际宽度(转成Dp方便使用)。 - 捕获组件真实尺寸:在删除按钮的
Modifier中添加onSizeChanged,获取其像素宽度并转换为Dp。 - 绑定动画目标值:将获取到的真实宽度作为动画的目标值,替代原来的固定
width。
完整代码示例
// 定义动画时长常量 private const val ANIMATION_DURATION = 300 @Composable fun SwipeToRevealDeleteButton() { var isRevealed by remember { mutableStateOf(false) } // 存储删除按钮的实际宽度(初始为0.dp) var deleteButtonWidth by remember { mutableStateOf(0.dp) } val transition = updateTransition(isRevealed, label = "revealTransition") // 动画:从0过渡到删除按钮的实际宽度 val revealWidth by transition.animateDp( label = "revealWidth", transitionSpec = { tween(ANIMATION_DURATION) }, targetValueByState = { if (it) deleteButtonWidth else 0.dp } ) Row( modifier = Modifier .fillMaxWidth() .background(Color.LightGray) .swipeable( state = rememberSwipeableState(isRevealed), anchors = mapOf( 0f to false, deleteButtonWidth.toPx() to true ), thresholds = { _, _ -> FractionalThreshold(0.5f) }, orientation = Orientation.Horizontal ) ) { // 主内容卡片 Box( modifier = Modifier .weight(1f) .height(60.dp) .background(Color.White) .padding(horizontal = 16.dp), contentAlignment = Alignment.CenterStart ) { Text("滑动显示删除按钮") } // 删除按钮:通过onSizeChanged获取wrap_content的实际宽度 Box( modifier = Modifier .width(revealWidth) // 用动画值控制宽度 .height(60.dp) .background(Color.Red) .onSizeChanged { size -> // 将像素宽度转换为Dp deleteButtonWidth = with(LocalDensity.current) { size.width.toDp() } }, contentAlignment = Alignment.Center ) { Text("删除", color = Color.White) } } }
关键细节说明
onSizeChanged的作用:当删除按钮完成布局后,会回调其真实尺寸(此时的宽度就是wrap_content对应的实际宽度),我们将其转换为Dp后保存到状态中。- 动画绑定:使用
animateDp直接处理Dp值的动画,比手动处理Float更直观,避免单位转换错误。 - 滑动逻辑:结合
swipeable实现侧滑交互,锚点直接使用删除按钮的实际宽度,确保滑动距离刚好完全显示按钮。
内容的提问来源于stack exchange,提问作者HAN-007
相关产品推荐
相关产品推荐

