Lottie — 是 Airbnb 的一个开源库,通过 Bodymovin 插件将 Adobe After Effects 中导出的矢量动画以 JSON 格式播放。动画以编程方式渲染,在任何屏幕分辨率下都不会损失质量。根据 GitHub(2026)的数据,Lottie 在 iOS、Android 和 Web 上的超过 50,000 个项目中使用。有关其他动画类型的更多信息,请阅读动画通用指南。
要点
Lottie — 是一个跨平台库,用于播放矢量动画,由 Airbnb 于 2015 年开发。它解决了重型视频文件和光栅精灵表的问题:设计师在 After Effects 中创建动画,通过 Bodymovin 导出到 JSON,然后开发者将此文件嵌入到移动应用中。Lottie 根据平台通过 Canvas、Core Animation 或 Skia 以编程方式渲染动画。
Lottie 的主要优势 — 矢量动画可在任何屏幕上无损缩放:从 Apple Watch 到 4K 电视。JSON 动画文件的大小通常为 5–50 KB,比同等视频文件小几十倍。根据 Airbnb Engineering(2025)的数据,Lottie 支持 Adobe After Effects 超过 80% 的功能,包括蒙版、效果、曲线和表达式。
Bodymovin — 是 After Effects 的一个插件(免费,GitHub),它将合成序列化为 Lottie 运行时能理解的 JSON 格式。支持 After Effects CC 2018 及更新版本。对于具有大量关键帧的复杂动画,建议使用 dotLottie — 一种基于 Lottie JSON 但经过压缩并打包到一个文件中的格式。
Lottie 使用分层渲染架构,根据平台能力进行调整。在 Android 上,动画通过 Canvas API 绘制 — Lottie 自己的渲染器(LottieDrawable),不使用系统动画。在 iOS 上,Lottie 依赖于 Core Animation Layers,提供高性能和 60 FPS。在 Flutter 上,Lottie 通过 CustomPainter 使用 Skia Canvas。
渲染经过三个阶段:JSON 解析 — 在 LottieComposition 中分析动画(所有图层、形状、关键帧);插值 — 考虑缓动曲线计算关键帧之间的中间值;绘制 — 在 Canvas 上或通过 Core Animation 渲染当前帧。Lottie 支持硬件加速:在 Android 上 — 通过带有 Hardware Accelerator 的 Canvas 加速,在 iOS 上 — 通过带有内置 GPU 加速的 CALayer Core Animation。
| 平台 | 渲染器 | 硬件加速 | 库 |
|---|---|---|---|
| Android | Canvas (LottieDrawable) | Hardware Accelerator (API 14+) | com.airbnb.lottie |
| iOS | Core Animation (CALayer) | GPU (Metal, OpenGL) | Lottie-iOS |
| Flutter | Skia Canvas (CustomPainter) | Impeller (Flutter 3.16+) | lottie_flutter |
| React Native | Native bridge | 取决于平台 | lottie-react-native |
在 Android 上,LottieAnimationView 扩展了 AppCompatImageView 并接管了整个加载和渲染循环。JSON 文件放置在 res/raw 或 assets 文件夹中。LottieAnimationView 支持播放管理 — play、pause、resume、setFrame、setProgress、repeat、speed — 以及通过 AnimatorUpdateListener 和 AnimatorListener 进行监听。
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/animationView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:lottie_rawRes="@raw/loading_animation"
app:lottie_autoPlay="true"
app:lottie_loop="true" />
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieListener
// 以编程方式配置 LottieAnimationView
val lottieView = LottieAnimationView(context).apply {
setAnimation(R.raw.celebrate_animation)
repeatCount = ValueAnimator.INFINITE
speed = 1.5f
addAnimatorUpdateListener { animator ->
val progress = animator.animatedValue as Float
progressBar.progress = (progress * 100).toInt()
}
playAnimation()
}
// 从 assets 加载和缓存
lottieView.setAnimation("animations/confetti.json")
lottieView.setCacheStrategy(LottieAnimationView.CacheStrategy.Strong)
// LottieDrawable — 无需视图的自定义绘制
val drawable = LottieDrawable().apply {
setComposition(
LottieCompositionFactory.fromRawRes(context, R.raw.star)
.addListener { composition -> composition?.let { setComposition(it); play() } }
)
}
Android 最佳实践:对于经常重复的动画,使用 setCacheStrategy(CacheStrategy.Strong) — 合成缓存在内存中,每个新实例不会重新解析 JSON。对于列表(RecyclerView),使用带有 enableMergePathsForKitKatAndAbove(true) 和 disableExtraScaleModeForOlderWorkarounds() 的 LottieAnimationView 以优化渲染。对于透明背景的动画,设置 android:layerType="hardware" 以启用 GPU 加速。
在 iOS 上,AnimationView — 是 Lottie 用于 UIKit 和 SwiftUI 的主要类。它通过 Swift Package Manager 或 CocoaPods 连接。JSON 文件被添加到项目的 bundle 中。AnimationView 自动确定 scale(屏幕的逻辑密度)并使用 Core Animation 以 60 FPS 渲染图层。
import Lottie
// UIKit:带手动控制的 AnimationView
let animationView = AnimationView(name: "confetti")
animationView.frame = view.bounds
animationView.contentMode = .scaleAspectFit
animationView.loopMode = .loop
animationView.animationSpeed = 1.5
animationView.play(fromProgress: 0, toProgress: 0.5) { finished in
print("动画段已完成:\(finished)")
}
view.addSubview(animationView)
// UIKit:带进度的动画(用于绑定到事件)
animationView.play(fromFrame: AnimationFrameTime(30),
toFrame: AnimationFrameTime(90))
// SwiftUI:LottieView 作为 UIViewRepresentable
import Lottie
import SwiftUI
struct LottieView: UIViewRepresentable {
let name: String
var loopMode: LottieLoopMode = .loop
@Binding var progress: CGFloat
func makeUIView(context: Context) -> AnimationView {
let view = AnimationView(name: name)
view.contentMode = .scaleAspectFit
view.loopMode = loopMode
return view
}
func updateUIView(_ uiView: AnimationView, context: Context) {
uiView.currentProgress = progress
}
}
// 在 SwiftUI 中使用
LottieView(name: "loading", progress: $animationProgress)
.frame(width: 100, height: 100)
iOS 最佳实践:对于加载后立即开始的动画,使用带有 loopMode = .playOnce 的 animationView.play(fromProgress: 0, toProgress: 1) 用于一次性强调效果。对于 UITableView/UICollectionView 中的 Lottie,使用通过 LottieAnimation.cached 缓存动画文件的 AnimationView。渲染大量图层(50+)可能导致 FPS 下降 — 在这种情况下,启用 renderingEngine = .mainThread(默认)或 macOS 的 .coreAnimation。
Lottie 与视频文件有根本区别:它不存储像素,而是描述矢量形状、它们的转换和随时间变化的曲线。视频(MP4、WebM)— 是固定分辨率的光栅帧序列。差异体现在文件大小、缩放质量、交互性和性能上。
| 参数 | Lottie (JSON) | 视频 (MP4) | GIF |
|---|---|---|---|
| 文件大小 | 5–50 KB | 200–2000 KB | 500–5000 KB |
| 缩放质量 | 矢量(无限) | 固定(像素) | 固定 |
| 交互性 | 进度、速度、暂停、颜色变化 | 无 | 无 |
| Alpha 通道(透明度) | 原生 | 需要编解码器 | 支持 |
| 性能(CPU) | 低负载 | 中等(解码) | 高(光栅解码) |
何时选择 Lottie:加载图标、点赞/反应动画、引导页、按钮强调微动画。对于具有 3D 效果、逼真照明或照片级真实角色的复杂场景,视频仍然是更实用的选择。Lottie 不适合播放长场景(超过 10 秒)— 一个动画的最佳时长为 2–5 秒。
Lottie 性能 取决于图层数量、蒙版和效果的复杂性以及渲染器。为了在中端设备上保持 60 FPS,请遵循建议:将每个场景的图层数量限制在 30–40,避免重叠的嵌套预合成,为复杂动画使用 dotLottie。
// 针对 RecyclerView 优化 Lottie
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieDrawable
import com.airbnb.lottie.LottieCompositionFactory
// 在内存中缓存合成
private val cache = LottieCompositionFactory.setCacheStrategy(CacheStrategy.Strong)
// LottieAnimationView 池用于重用
class LottiePool {
private val pool = LinkedList<LottieAnimationView>()
fun acquire(context: Context): LottieAnimationView {
return pool.poll() ?: LottieAnimationView(context)
}
fun release(view: LottieAnimationView) {
view.pauseAnimation()
view.cancelAnimation()
pool.add(view)
}
}
// 禁用不必要的功能
lottieView.enableMergePathsForKitKatAndAbove(true)
lottieView.setHardwareAcceleration(true)
lottieView.setMaxFrame(60) // 限制帧数
额外优化:为 Android 4.4+ 设备启用 enableMergePathsForKitKatAndAbove(true) — 这会将重叠的轮廓合并到一条路径中,减少绘制调用次数。使用 dotLottie 替代 JSON — 二进制格式通过 protobuf 序列化将动画压缩 50–80%,从而缩短解析时间。对于 RecyclerView 中的动画,设置 repeatCount = 0(播放一次)并在滚动时通过 recyclerView.addOnScrollListener 停止动画。根据 Airbnb Engineering Blog(2025),这些措施可将 CPU 负载降低高达 40%。
常见问题解答
使用 dotLottie — 基于 protobuf 的二进制格式,可将 JSON 压缩 50–80%。在 After Effects 中通过 Bodymovin 导出时设置「Glyphs」= None(如果不需要文字),关闭额外的参考线和参考线图层。在导出前删除不可见图层和透明度为 0% 的图层。
检查最低 SDK 版本:Android 版 Lottie 支持 API 14+,但某些效果(Path Morphing, Gradient)仅适用于 API 21+。在 iOS 上,Lottie 需要 iOS 11+。对于旧设备,使用后备方案 — 动画中的静态 PNG 帧。通过 LottieCompositionFactory 异步加载动画,并通过 LottieListener.onFailure 处理错误。
可以,通过 LottieDynamicProperties 或 KeyPath。在 After Effects 中设置图层名称(例如「icon-fill」),然后在代码中:lottieView.addValueCallback(KeyPath(「icon-fill」), LottieProperty.COLOR) { Color.GREEN }。这允许根据应用主题自定义动画,而无需创建重复文件。对于 iOS,使用 AnimationView.setValueProvider(ColorValueProvider)。
Lottie — 用于播放来自 After Effects 的预制动画的格式。Rive — 具有状态机、触发器和输入的交互式动画。Lottie 适用于被动动画(加载、点赞、欢迎页面)。Rive — 适用于游戏、交互式 UI 元素、对用户操作提供反馈的动画。Rive 需要自己的编辑器,Lottie 通过熟悉的 After Effects 工作。
在 Android 上:lottieView.addAnimatorListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { ... } })。在 iOS 上:animationView.play { finished in }。在 SwiftUI 中:使用带有 onChange 的 Binding 来追踪 currentProgress。对于 Kotlin Multiplatform,使用 lottie-compose 库中的 LottieAnimatable。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。