Jetpack Compose 动画Modifier.animateItem()

在 Jetpack Compose 中,Modifier.animateItem() 是从 Compose 1.7.0 开始引入的一个强大且常用的修饰符(它替代了早期被废弃的 animateItemPlacement)。

一、 animateItem 的核心作用

Modifier.animateItem() 专门用于 LazyColumn 或 LazyRow 中,为列表项的动态变化提供开箱即用的平滑过渡动画。它能够同时处理以下三种场景:

  1. 位置重排(Reordering /
    Placement):当列表项因为插入、删除或排序改变位置时,它们会平滑地滑动到新位置,而不是瞬间"闪现"。
  2. 出现/插入(Appearance / Fade In):当有新项被插入到列表中时,它会以淡入(Fade In)等动画形式出现。
  3. 消失/删除(Disappearance / Fade Out):当项被从列表中移除时,它会以淡出动画形式消失。

二、 使用的核心前提

必须提供稳定的 key:在 LazyColumn 的 items() 中,必须通过 key 参数为每个 item 指定一个唯一且稳定的标识(如数据的 ID)。如果使用默认的索引(index)或不传 key,Compose 将无法在数据发生变动时正确追踪身份,从而导致动画失效或混乱。

三、 完整代码例子

下面的例子展示了一个包含添加、删除和随机打乱(重排)功能的列表,完美应用了 Modifier.animateItem()

复制代码
data class Task(val id: Int, val title: String)

@Composable
fun AnimatedItemListExample() {
    // 模拟列表数据源
    var tasks by remember {
        mutableStateOf(
            listOf(
                Task(1, "学习 Jetpack Compose"),
                Task(2, "了解 animateItem 作用"),
                Task(3, "编写示例代码")
            )
        )
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        // 操作按钮区域
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(bottom = 16.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            Button(onClick = {
                val newId = (tasks.maxOfOrNull { it.id } ?: 0) + 1
                // 在顶部插入新项
                tasks = listOf(Task(newId, "新任务 $newId")) + tasks
            }) {
                Text("添加")
            }

            Button(onClick = {
                // 随机打乱列表顺序(测试重排动画)
                tasks = tasks.shuffled()
            }) {
                Text("打乱排序")
            }
        }

        // 列表区域
        LazyColumn(
            modifier = Modifier
                .fillMaxWidth()
                .weight(1f),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            // 【关键点】:必须提供 key,否则动画无法正确追踪目标
            items(
                items = tasks,
                key = { task -> task.id }
            ) { task ->
                Card(
                    modifier = Modifier
                        .fillMaxWidth()
                        // 【关键点】:在最外层 Modifier 中链式调用 animateItem()
                        .animateItem(
                            // 可选:自定义动画效果(不传则使用默认的优雅弹簧动画)
                            fadeInSpec = tween(durationMillis = 300),
                            fadeOutSpec = tween(durationMillis = 300),
                            placementSpec = spring(stiffness = 300f)
                        )
                ) {
                    Row(
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(16.dp),
                        horizontalArrangement = Arrangement.SpaceBetween,
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Text(text = task.title, style = MaterialTheme.typography.bodyLarge)
                        
                        IconButton(onClick = {
                            // 删除当前项(测试删除渐隐动画)
                            tasks = tasks.filter { it.id != task.id }
                        }) {
                            Icon(Icons.Default.Delete, contentDescription = "删除")
                        }
                    }
                }
            }
        }
    }
}

四、 自定义动画效果

animateItem() 允许你传参来精确控制各个动画的贝塞尔曲线或物理弹簧效果:

  • fadeInSpec: 控制元素出现时的渐入动画(如 tween(200))。
  • fadeOutSpec: 控制元素消失时的渐出动画(如 tween(200))。
  • placementSpec: 控制元素位置移动时的滑动动画(如默认的 spring() 弹簧效果或 tween())。
相关推荐
2401_885885042 小时前
巴林语音通知接口如何对接?系统告警语音API接入教程
android·前端·网络·python·语音识别
收纳过往2 小时前
数据库加索引的时机:慢查询日志说话
android·开发语言·数据库·python·低代码·rxjava
狂热开发者3 小时前
车载中控要给鸿蒙用户,能不能和 Android 共用一个二维码?
android·华为·harmonyos
.Bryce.4 小时前
T2-LLM评测不等于Agent评测
android·java·人工智能·后端·gpt·agent·1024程序员节
美狐美颜SDK开放平台5 小时前
视频美颜SDK如何应对快速转头与大幅度面部动作?
android·人工智能·ios·音视频·直播美颜sdk·视频美颜sdk
2601_968900775 小时前
玻璃深加工的工艺窗口:4 道工序的温度与时间参数边界
android·java·javascript
好的佩奇015 小时前
Dart 之类修饰符
android·flutter·dart
YB13755 小时前
Jetpack Compose 动画Modifier.animateContentSize()
android
事圆则缓5 小时前
Android 版本号、API Level 和 JDK 版本有什么关系?
android