Jetpack Compose 动画实战:让你的 UI 动起来

传统的 Android View 动画体系(AlphaAnimation, ObjectAnimator, MotionLayout 等)往往割裂且复杂。而 Jetpack Compose 的动画 API 设计得非常直观声明式------你只需要描述"状态 A"和"状态 B",Compose 会自动帮你处理中间的过渡。

本文将由浅入深,带你掌握 Compose 动画的三板斧。

1. 入门:属性动画 (animate*AsState)

这是最简单、最常用的动画方式。当你只需要改变某个单一属性(如颜色、大小、透明度)时,使用它准没错。

场景:点击按钮,方块变大,颜色变红。

Kotlin 复制代码
@Composable
fun SimpleAnimationDemo() {
    // 1. 定义状态
    var isBig by remember { mutableStateOf(false) }

    // 2. 定义动画值 (Compose 会自动处理从当前值到目标值的平滑过渡)
    val size by animateDpAsState(
        targetValue = if (isBig) 100.dp else 50.dp,
        label = "size" // 用于 Layout Inspector 调试
    )
    val color by animateColorAsState(
        targetValue = if (isBig) Color.Red else Color.Blue,
        label = "color"
    )

    // 3. 使用动画值
    Box(
        modifier = Modifier
            .size(size)
            .background(color)
            .clickable { isBig = !isBig }
    )
}

常用的 API 有:

  • animateDpAsState:用于 dp 单位的值(如宽高、padding、offset)。
  • animateFloatAsState:用于浮点数值(如透明度 alpha、缩放 scale、旋转角度)。
  • animateColorAsState:用于颜色值(如背景色、文字颜色),会自动处理 RGB 的平滑过渡。
  • animateIntAsState:用于整数值(如列表索引、百分比进度)。

2. 进阶:可见性动画 (AnimatedVisibility)

在 View 体系中,隐藏/显示通常只是 View.GONE / View.VISIBLE 的生硬切换。Compose 提供了 AnimatedVisibility,让组件的出现和消失变得丝般顺滑。

场景:点击按钮,展开/收起一段文本。

Kotlin 复制代码
@Composable
fun VisibilityDemo() {
    var visible by remember { mutableStateOf(true) }

    Column {
        Button(onClick = { visible = !visible }) {
            Text(if (visible) "Hide" else "Show")
        }

        AnimatedVisibility(
            visible = visible,
            // 自定义进入动画:从顶部滑入 + 淡入
            enter = slideInVertically() + fadeIn(),
            // 自定义退出动画:向顶部滑出 + 淡出
            exit = slideOutVertically() + fadeOut()
        ) {
            // 这里放你想隐藏/显示的内容
            Text(
                text = "Peek-a-boo! I see you!",
                modifier = Modifier.padding(16.dp).background(Color.Yellow)
            )
        }
    }
}

Tips :你可以通过 + 号组合多个动画效果(如"淡入"+"放大")。


3. 高级:布局内容切换 (AnimatedContent)

当你需要根据状态完全替换 界面上的某个部分(例如:从"加载中"切换到"数据内容",或者数字的滚动变化)时,AnimatedContent 是神器。

场景:一个简单的计数器,数字变化时有类似老式翻页钟的上下滚动效果。

Kotlin 复制代码
@Composable
fun CounterDemo() {
    var count by remember { mutableIntStateOf(0) }

    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Button(onClick = { count++ }) { Text("Add") }

        AnimatedContent(
            targetState = count,
            transitionSpec = {
                // 定义:新数字从下往上进,旧数字从上往出
                // (slideInVertically { height -> height } + fadeIn())
                // .togetherWith(slideOutVertically { height -> -height } + fadeOut())
                
                // 简化写法:垂直滚动动画
                slideInVertically { it } togetherWith slideOutVertically { -it }
            },
            label = "counter"
        ) { targetCount ->
            // 这里不仅可以是 Text,也可以是复杂的 Composable
            Text(
                text = "$targetCount",
                style = MaterialTheme.typography.displayLarge
            )
        }
    }
}

4. 核心配置:动画规格 (AnimationSpec)

几乎所有的 Compose 动画 API 都有一个 animationSpec 参数,用于控制动画的速度曲线质感

A. 弹簧效果 (Spring) - 默认且推荐

如果你不设置,Compose 默认使用 spring()。它模拟物理世界的弹簧,没有固定的时长,只有阻尼和刚度,看起来最自然。

Kotlin 复制代码
animateDpAsState(
    targetValue = 100.dp,
    animationSpec = spring(
        dampingRatio = Spring.DampingRatioMediumBouncy, // 弹性系数 (高弹/低弹/无弹)
        stiffness = Spring.StiffnessLow // 刚度 (越低越慢且软)
    )
)

B. 补间动画 (Tween)

传统的基于时长的动画。

Kotlin 复制代码
animateDpAsState(
    targetValue = 100.dp,
    animationSpec = tween(
        durationMillis = 1000, // 1秒
        easing = LinearOutSlowInEasing // 缓动曲线
    )
)

C. 关键帧 (Keyframes)

用于精细控制动画过程中的每一个节点。

Kotlin 复制代码
animateDpAsState(
    targetValue = 100.dp,
    animationSpec = keyframes {
        durationMillis = 1000
        0.dp at 0 // 开始时 0dp
        50.dp at 200 // 200ms 时到达 50dp (快)
        100.dp at 1000 // 结束时 100dp
    }
)

5. 总结与建议

Compose 的动画系统非常庞大,但对于 90% 的日常开发,只需要记住以下决策路径:

  1. 只是改变某个属性值? -> 用 animate*AsState
  2. 让组件出现/消失? -> 用 AnimatedVisibility
  3. 两个组件互相切换? -> 用 AnimatedContent
相关推荐
researcher-Jiang9 分钟前
高性能计算之OpenMP——超算习堂学习1
android·java·学习
alexhilton1 小时前
Kotlin DSL深度解析:从Gradle脚本到构建你自己的DSL
android·kotlin·android jetpack
烽火聊员1 小时前
查看Android Studio错误日志
android·ide·android studio
星空语7 小时前
音频001_Android+Linux车载/手机音频全链路分层架构图
android·linux·音视频
CyL_Cly7 小时前
解决官网下载慢!Android Studio 最新版网盘下载
android·ide·android studio
智塑未来7 小时前
鸿蒙系统对比安卓、iOS,核心优势是什么?
android·ios·harmonyos
AI刀刀8 小时前
豆包智能体对话导出后,如何构建长期归档与高效检索体系?
android·人工智能·word·excel·ai导出鸭
初雪云9 小时前
iOS 上架入门:证书、描述文件、IPA 上传到底是什么关系?
android·ios·自动化·产品经理·iphone
玩机达人8812 小时前
一加12/Ace5/Ace3pro手机ColorOS16降级回锁BL熔断变黑砖怎么办
android·智能手机·电脑
Digitally12 小时前
使用 USB 数据线将文件从安卓设备传输到电脑
android·电脑