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
相关推荐
JMchen1231 小时前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
crmscs2 小时前
剪映永久解锁版/电脑版永久会员VIP/安卓SVIP手机永久版下载
android·智能手机·电脑
localbob2 小时前
杀戮尖塔 v6 MOD整合版(Slay the Spire)安卓+PC端免安装中文版分享 卡牌肉鸽神作!杀戮尖塔中文版,电脑和手机都能玩!杀戮尖塔.exe 杀戮尖塔.apk
android·杀戮尖塔apk·杀戮尖塔exe·游戏分享
机建狂魔2 小时前
手机秒变电影机:Blackmagic Camera + LUT滤镜包的专业级视频解决方案
android·拍照·摄影·lut滤镜·拍摄·摄像·录像
hudawei9962 小时前
flutter和Android动画的对比
android·flutter·动画
lxysbly4 小时前
md模拟器安卓版带金手指2026
android
儿歌八万首4 小时前
硬核春节:用 Compose 打造“赛博鞭炮”
android·kotlin·compose·春节
消失的旧时光-19437 小时前
从 Kotlin 到 Dart:为什么 sealed 是处理「多种返回结果」的最佳方式?
android·开发语言·flutter·架构·kotlin·sealed
有位神秘人7 小时前
kotlin与Java中的单例模式总结
java·单例模式·kotlin
Jinkxs7 小时前
Gradle - 与Groovy/Kotlin DSL对比 构建脚本语言选择指南
android·开发语言·kotlin