You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jetpack Compose中实现0至wrap_content的宽度动画?

解决Jetpack Compose滑动显示组件到wrap_content宽度的问题

要实现滑动后卡片宽度动画过渡到wrap_content尺寸,核心是获取目标组件(比如删除按钮)的实际渲染宽度,而非使用固定值。可以通过Modifier.onSizeChanged捕获组件的真实尺寸,再将其作为动画的目标值。

具体实现步骤

  1. 存储目标宽度状态:用remember保存目标组件的实际宽度(转成Dp方便使用)。
  2. 捕获组件真实尺寸:在删除按钮的Modifier中添加onSizeChanged,获取其像素宽度并转换为Dp。
  3. 绑定动画目标值:将获取到的真实宽度作为动画的目标值,替代原来的固定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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 06:01:00