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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 11:53:08