17、动画优化:属性动画原理、帧动画优化、转场动画性能、Lottie动画使用
动画这东西,说白了就是「视觉欺骗」。你让屏幕每秒刷新60次,每次画面变一点点,人眼就觉得「哇,好流畅」。但问题在于——Android的UI线程很脆弱,你稍微多干点活,掉帧就来了。
我个人习惯把动画优化放在性能优化的「甜点区」。为什么?因为修一个内存泄漏可能改半天代码,但优化一个动画,往往几行配置就能让体验上一个台阶。性价比极高。
属性动画的原理与性能要点
属性动画(ValueAnimator / ObjectAnimator)是Android 3.0之后的主力动画方案。它的核心机制其实不复杂:
- 时间插值器:把时间进度(0~1)映射到某个曲线值上
- 估值器:把插值器算出来的进度,转换成具体的属性值
- 刷新回调:每帧回调onAnimationUpdate,你在这里改View的属性
嗯,这里要注意一个关键点——属性动画并不直接操作View的绘制。它只负责算值,然后调用setter。真正触发重绘的是你setter里调用的invalidate()。所以如果你在onAnimationUpdate里做太多计算,UI线程就被卡住了。
核心原则:属性动画的性能瓶颈不在动画框架本身,而在你的回调函数里干了什么。
我在项目中遇到过一个问题:一个列表项的点赞动画,每次执行时都重新解析了一次SVG图标。结果动画一跑,列表就卡成PPT。后来改成预解析+缓存,瞬间丝滑。
帧动画优化——能不用就别用
帧动画(AnimationDrawable)的原理最简单:一帧一帧地换图片。但它的性能问题也最明显——内存爆炸。
你想想看,一个60帧的动画,每帧是一张1080p的PNG,每张图可能2~3MB。60张图全加载到内存里,就是120~180MB。这还不算解码时的临时内存。我见过一个App因为帧动画直接OOM的案例,当时排查了半天才发现是启动页的帧动画没做优化。
优化帧动画,我总结了几条铁律:
- 控制帧数:不要超过30帧,人眼其实分辨不出60帧的逐帧动画
- 使用WebP:同样的画质,WebP比PNG小30%~50%
- 按需加载:不要一次性把所有帧都decode到内存,用LRU缓存,只保留最近几帧
- 考虑替代方案:能用Lottie就用Lottie,能用属性动画就用属性动画
避坑指南:我曾经在一个手表表盘项目里用了帧动画做秒针旋转,每帧一张高清图。结果手表发热严重,电量哗哗掉。后来改成属性动画+Canvas绘制,功耗直接降了70%。帧动画真的只适合小尺寸、短时长的场景。
转场动画性能——别让过渡变成卡顿
转场动画(Activity过渡、Fragment过渡、共享元素过渡)是用户感知最明显的动画场景。做得好了,用户觉得「这App真精致」;做得差了,用户觉得「这App真卡」。转场动画的性能瓶颈通常出在:
- 布局层级过深:过渡时整个布局树都要参与测量和布局
- 过度绘制:转场过程中多个View重叠,GPU要处理大量透明混合
- 共享元素匹配:两个Activity之间的共享元素如果尺寸差异太大,缩放计算会消耗GPU
我个人习惯的做法是:
- 简化过渡View:只对关键元素做过渡动画,不要整个布局一起动
- 使用硬件加速:确保转场动画在硬件加速层上运行
- 预布局:在过渡开始前,提前把目标页面的布局计算好
小技巧:如果你用共享元素过渡,记得给两个View设置相同的transitionName,并且尽量保持宽高比一致。否则GPU要做非均匀缩放,性能会下降不少。
Lottie动画使用——现代App的标配
Lottie是Airbnb开源的一个动画库。它的核心思路是:设计师在After Effects里做动画,导出成JSON文件,然后Lottie在客户端用Canvas或OpenGL渲染出来。
为什么Lottie性能好?因为:
- 没有图片解码:JSON里存的是矢量路径和关键帧数据,不需要加载大图
- 增量渲染:Lottie只渲染变化的部分,不重绘整个画布
- 硬件加速友好:Lottie默认使用硬件加速层
我在项目中用Lottie替换过一个复杂的加载动画,原来用帧动画占了30MB内存,换成Lottie后只用了不到2MB。而且动画效果更平滑,因为Lottie支持60fps的插值渲染。
使用Lottie时要注意几点:
- 控制JSON大小:单个Lottie动画的JSON文件不要超过500KB,否则解析时间会很长
- 复用Animation:同一个动画不要创建多个LottieAnimationView实例,用缓存池
- 关闭自动播放:在列表中使用时,手动控制播放时机,避免滑动时触发动画
- 降低帧率:如果动画不需要60fps,可以设置setMaxFrame(30),省电又省CPU
经验之谈:Lottie虽然好,但也不是万能药。如果你的动画包含大量文字渲染或复杂渐变,Lottie的渲染性能会下降。这时候可以考虑用属性动画+自定义View来实现。
动画优化知识体系
下面这张图梳理了本章的核心逻辑,方便你对照排查问题:
性能对比一览
为了方便你选型,我把四种动画方案的核心指标整理成了表格:
| 动画类型 | 内存占用 | CPU负载 | GPU负载 | 适用场景 |
|---|---|---|---|---|
| 属性动画 | 低 | 中 | 低 | View属性变化、自定义动画 |
| 帧动画 | 高 | 低 | 中 | 短时小尺寸动画(不推荐) |
| 转场动画 | 中 | 中 | 高 | 页面切换、共享元素 |
| Lottie动画 | 低 | 低 | 中 | 复杂矢量动画、品牌动效 |
最后说一句——动画优化的本质,是把计算从UI线程挪走,把内存占用降下来,把GPU用起来。你只要记住这三条,遇到任何动画性能问题都能找到方向。
公众号:蓝海资料掘金营,微信deep3321