Jetpack Compose 动画AnimatedContent

在 Jetpack Compose 中,AnimatedContent 是 Crossfade 的"终极进阶版"。如果说 Crossfade 只能做简单的交叉淡入淡出,那么 AnimatedContent 则允许你为不同内容或状态之间的切换定制极其丰富的入场(Enter)与出场(Exit)动画组合。

它非常适合用于数字计数器滚动、多步骤引导页(Wizard)切换、或者带有方向感的 Tab 页面切换。

一、 核心作用与特点

  1. 灵活的入场与出场组合 (transitionSpec)
    你可以根据"旧状态"与"新状态"的变化关系(比如数字变大还是变小、向左切还是向右切),动态决定是让新内容从上方滑入、下方滑入,还是配合缩放和透明度渐变。
  2. 自动容器尺寸动画 (SizeTransform)
    当切换前后的两个布局组件尺寸大小不一致时,AnimatedContent 能够自动、平滑地过渡外层容器的宽高,而不会产生突兀的瞬间跳变。
  3. 基于状态驱动
    和 Crossfade 类似,它接受一个 targetState。只要这个状态发生变化,它就会自动卸载旧内容、渲染新内容并播放配置好的过渡动画。

二、 典型使用示例(带方向感知的计数器)

以下代码展示了如何使用 AnimatedContent 实现一个数字计数器:当数字增大时新数字从下方滑入,减小时从上方滑入:

复制代码
@Composable
fun AnimatedCounterDemo() {
    var count by remember { mutableStateOf(0) }

    Column(
        modifier = Modifier.padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // 控制按钮
        Row(verticalAlignment = Alignment.CenterVertically) {
            Button(onClick = { count-- }) { Text("- 减少") }
            Spacer(modifier = Modifier.width(16.dp))
            Button(onClick = { count++ }) { Text("+ 增加") }
        }

        Spacer(modifier = Modifier.height(24.dp))

        // 使用 AnimatedContent 处理内容切换
        AnimatedContent(
            targetState = count,
            transitionSpec = {
                // 根据数值大小判断动画方向
                if (targetState > initialState) {
                    // 变大:新内容从下方滑入并淡入,旧内容向上方滑出并淡出
                    (slideInVertically { height -> height } + fadeIn()) togetherWith
                            (slideOutVertically { height -> -height } + fadeOut())
                } else {
                    // 变小:新内容从上方滑入并淡入,旧内容向下方滑出并淡出
                    (slideInVertically { height -> -height } + fadeIn()) togetherWith
                            (slideOutVertically { height -> height } + fadeOut())
                }.using(
                    SizeTransform(clip = false) // 允许动画过程中超出裁剪区域
                )
            },
            label = "CounterAnimation"
        ) { targetCount ->
            // 根据 targetCount 渲染对应的内容
            Text(
                text = "$targetCount",
                fontSize = 48.sp,
                fontWeight = FontWeight.Bold,
                color = Color.Blue
            )
        }
    }
}
相关推荐
HQL_seven1 小时前
【Android】BroadcastReceiver 详解
android
_祝你今天愉快2 小时前
Paint Cavans高级绘制:[二] Paint-滤镜,XFERMODE
android
小乖写代码2 小时前
字段获取代码(Android) · Android Input Examples
android·whatsapp·账号注册
booboosui3 小时前
停一个活只有杀进程:界面上少了「说点要求」
android
传奇开心果编程5 小时前
【Flutter踩坑排雷】第28课:平台目录缺失与修复坑|`flutter create` 的“重建”与“覆盖”边界
android·flutter·ios·移动开发·跨平台·dart·声明式ui
longxibo14 小时前
【AIBIZ低代码平台:能长出业务系统的平台】
android·低代码·rxjava
AI_Gump1 天前
Harness篇|DeepSeek Harness 上手机:五条安卓移植路线与 App 内 Linux 拆解
android·linux·人工智能·智能手机·deepseek
疯华整猫1 天前
否决 Flutter 提案那天,我发现自己也说不清 Framework 管什么
android
传奇开心果编程2 天前
【Flutter踩坑排雷】第25课:ScrollController 误用坑|跳转失效、监听泄漏与“控制器未附加”
android·flutter·ios·移动开发·跨平台·dart·声明式ui
慕容雪_2 天前
Capacitor8-Android打包完整手册
android·打包·capacitor