Android Jetpack Compose帧动画(Animatable、AVD)

前言

在 Jetpack Compose 中实现多帧动画(即逐帧动画,类似 GIF 的效果),主要有以下几种方式:

方法 适用场景 备注
mutableStateOf + LaunchedEffect 任意多帧 PNG/JPG 资源 最灵活、最常用
AnimatedImageVector Animated Vector Drawable 仅限矢量动画
AndroidView + AnimationDrawable 兼容旧逻辑 不推荐用于新项目
Lottie 复杂动画

使用Animatable + LaunchedEffect

手动控制帧切换

Jetpack Compose 本身没有直接提供“逐帧动画”的内置组件,但你可以通过组合 remembermutableStateOfLaunchedEffect 和协程来实现。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Composable
fun FrameAnimation(
frameIds: List<Int>, // 图片资源 ID 列表,如 listOf(R.drawable.frame1, R.drawable.frame2, ...)
durationPerFrame: Int = 100, // 每帧持续时间(毫秒)
isPlaying: Boolean = true,
modifier: Modifier = Modifier
) {
val currentFrame = remember { mutableStateOf(0) }
val totalFrames = frameIds.size

LaunchedEffect(isPlaying) {
if (!isplaying) return@LaunchedEffect
while (true) {
delay(durationPerFrame.toLong())
currentFrame.value = (currentFrame.value + 1) % totalFrames
}
}

Image(
painter = painterResource(id = frameIds[currentFrame.value]),
contentDescription = null,
modifier = modifier
)
}

注意💡:

你需要提前将所有帧作为 drawable 资源放入项目中。

优化建议

  • 预加载图片:避免在每一帧都调用 painterResource(它内部有缓存,但最好确保资源已加载)。
  • 控制生命周期:通过 isPlaying 参数控制动画启停,避免内存泄漏。
  • 使用 rememberUpdatedState:如果 frameIdsdurationPerFrame 可能变化,需用 rememberUpdatedState 包裹以避免重启协程。

使用AnimatedImageVector

仅适用于 VectorDrawable 动画

Animated Vector Drawable 是一种基于 XML 的 Android 原生动效格式,结合了矢量图形与属性动画,适合实现轻量、流畅、可缩放的图标动画。

示例代码

如果你的动画是 Animated Vector Drawable(AVD),可以使用:

1
2
3
4
5
6
7
8
val image = AnimatedImageVector.animatedVectorResource(R.drawable.animated_vector)

var atEnd by remember { mutableStateOf(false) }

Image(
painter = remember { image.painterFor(atEnd) },
contentDescription = null
)

但这只适用于 Android 原生支持的 AnimatedVectorDrawable,不适用于普通位图(PNG/JPG)的逐帧动画。

生成工具

Shape Shifter

使用传统View动画(不推荐)

虽然可以在 Compose 中嵌入 AndroidView 并使用传统 ImageView + AnimationDrawable,但这违背了 Compose 的声明式理念,且性能和状态管理不如纯 Compose 方案。

使用动画库Lottie

Jetpack Compose 中使用 Lottie(由 Airbnb 开发的动画库)非常方便,官方提供了对 Compose 的原生支持。

在 Jetpack Compose 中使用 Lottie 只需三步:

  1. 添加 lottie-compose 依赖
  2. 放入 .jsonres/raw
  3. rememberLottieComposition + animateLottieCompositionAsState + LottieAnimation

它比 AVD 更强大,适合复杂动效;而 AVD 更适合轻量、原生图标动画。两者可根据场景搭配使用。

详细使用

Android Jetpack Compose帧动画-Lottie使用 | 码客说