- UI组件
- 移动开发
- 图形学
【免费下载链接】lottie-android
Render After Effects animations natively on Android and iOS, Web, and React Native
本文以 lottie-android 仓库中的 DESIGNER_NOTES.md 为骨架,逐条展开设计师在使用 Adobe After Effects + Bodymovin 制作 Lottie 动画时必须遵守的 5 条铁律,并结合仓库源码(解析器、图层渲染、警告机制)验证每条规范的底层原因与失效后果,帮助设计师与 Android 工程师在产线协作中提前规避动画不兼容、性能劣化与视觉偏差问题。
一、背景:Bodymovin 导出后的“原生渲染”不是魔法
Lottie 的核心能力,是把设计师在 Adobe After Effects 中用 Bodymovin 插件导出的 JSON 动画,在 Android 端以原生代码逐帧渲染(参见 README.md 对项目能力的描述)。它既不依赖 GIF,也不依赖 WebView,而是把 JSON 里的图层、形状、关键帧、蒙版等描述直接翻译成 Android 的Canvas绘制指令。
然而,JSON 能描述的,并不等于 Lottie 能渲染的。After Effects 本身拥有远超 Bodymovin 导出范围的特性集,而 Lottie 又只实现了 Bodymovin 导出内容的一个子集。因此仓库根目录下这份极简的 DESIGNER_NOTES.md 实际上就是官方给设计师划出的兼容性红线——全文仅 5 条,但每一条都直接决定动画能否在 Android 上正确、流畅地播放。下面逐条展开,并用源码佐证。
二、注意事项 1:表达式(Expressions)不支持
原文:Expressions are not supported.
After Effects 的表达式(JavaScript 驱动的动态属性)在 Bodymovin 导出时,通常会以字符串形式把表达式源码塞进 JSON 属性节点,Lottie 无法执行这段 JavaScript,只能选择忽略。
从源码可以确认,lottie-android 的解析器在遇到以字符串形式出现的属性值时,会直接判定“存在表达式”并跳过该值,同时向组合体写入一条警告:
- AnimatablePathValueParser.java 的
parseSplitPath方法中,当位置属性(x/y)的 JSON 值是字符串(而非数字或关键帧数组)时,置hasExpressions = true并reader.skipValue()跳过,最后调用composition.addWarning("Lottie doesn't support expressions.")。 - KeyframesParser.java 在解析关键帧数组时同样存在
composition.addWarning("Lottie doesn't support expressions.")的分支。
这里的关键事实是:表达式被跳过意味着该属性将丢失动画。例如一个用表达式驱动的位置循环,导出后该属性可能退化为静态值或首个关键帧值,画面表现与 AE 里预览的完全不同。因此设计师必须在 AE 中把表达式烘焙(bake)成关键帧后再导出,或直接用关键帧实现等价效果。
三、注意事项 2:文本(Text)不支持
原文:Text is not supported.
需要精确理解这句话的边界:它指的是设计师在 AE 中随意排版、随意使用字体的文本图层,Lottie 不保证还原。原因是文本的渲染依赖字体文件的字形数据:Bodymovin 会把文本内容、字体信息与文档数据导出到 JSON,而 Android 端必须能拿到匹配的字体字形才能绘制。
lottie-android 确实实现了完整的文本渲染管线,并非“完全没有文本能力”:
- TextLayer.java 是专门负责文本图层的渲染类,内部维护了
fillPaint/strokePaint、字符到ContentGroup的映射(contentsForCharacter)、以及基于DocumentData的段落排版逻辑(代码注释明确提到“If this is paragraph text, one line may wrap depending on the size of the document data box”)。 - 仓库中还提供
TextDelegate(见 TextDelegate.java)与LottieProperty.TEXT等运行时替换文本的能力。
但注意,这条注意事项对设计师的实际含义是:
- 字形依赖字体资源:若动画引用的字体未随 JSON 提供给 Android 端,文本会显示为错误字形或回退字体;
- 复杂排版不保证:行距、字距、基线、文本动画(如逐字/逐行动画)等只有在字体资源齐备且属性被 Bodymovin 正确导出的前提下才能还原;
- 不要依赖文本做关键画面:在无法预知运行环境字体的跨端场景(Android / iOS / Web),最稳妥的做法是把文字在 AE 里转为形状图层或矢量轮廓后导出,彻底消除字体依赖。
四、注意事项 3:Illustrator 图层必须先转换为形状图层
原文:If you have an Illustrator layer, convert it to a shape layer or else it will be exported as a bitmap.
当 AE 项目中直接放置 Illustrator 文件(AI 图层)而未转换为形状图层时,Bodymovin 通常只能把它当作位图(bitmap)资源导出,而不是矢量路径。位图会带来两重代价:包体变大(图片需要作为资源打进 APK)、缩放失真(位图放大后发虚)。
源码侧同样印证了这一点——解析器会主动识别这类图层并写入警告:
- LayerParser.java 在解析图层时检测
layerName.endsWith(".ai")或cl(class)等于"ai"的情况,随后调用composition.addWarning("Convert your Illustrator layers to shape layers.")。 - LottieCompositionMoshiParser.java 中也有一段与形状/图层类型相关的警告文本,提醒把 Illustrator 图层转换为形状后再配合使用。
这条规范的正确做法是:在 AE 中右键 Illustrator 图层 → 选择“从矢量图层创建形状”(Create Shapes from Vector Layer),把 AI 路径转成可导出的矢量形状,然后再交给 Bodymovin 导出。这样动画里保存的是路径数据而非图片,渲染无损且体积更小。
五、注意事项 4:蒙版(Mask)与蒙板(Matte)内容越小,性能越好
原文:The smaller the content in a masked or matted layer is, the better the performance will be.
蒙版(Mask)和轨道蒙板(Track Matte)的渲染在 Android 上是离屏绘制:lottie-android 需要先把被裁剪/被蒙板的内容单独绘制到离屏缓冲,再通过遮罩合成回主画布。离屏缓冲的尺寸与蒙版/蒙板区域的包围盒(bounds)直接相关,区域越大,需要填充的像素越多,每帧的 GPU 开销就越高。
从实现上看:
- BaseLayer.java 的绘制流程中,当图层带有蒙版或蒙板(
hasMatteOnThisLayer()/hasMasksOnThisLayer())且混合模式非 NORMAL 时,会进入computeBounds分支——也就是先计算包围盒再走离屏合成路径,而不是走drawLayer直绘捷径(见同文件第 265-276 行的快速路径判断)。 - 第 508-543 行进一步展示了蒙版的多种合成方式(
applyAddMask、applyInvertedAddMask、applyIntersectMask、applyInvertedIntersectMask、applyInvertedSubtractMask等),每种都涉及离屏裁剪计算。
因此对设计师的实操建议是:
- 蒙版/蒙板应尽量贴近被裁剪内容本身,不要用远超内容范围的超大遮罩框;
- 避免对整幅全屏大图做蒙版/蒙板,改为先裁剪内容再叠加;
- 能合并的多个蒙版尽量合并,减少离屏渲染的层数。
这条规则直接决定动画在低端 Android 设备上的帧率表现。
六、注意事项 5:透明度按元素应用,而非按图层/组应用
原文:Opacity is applied to individual elements not entire layers/groups. This can affect the appearance of overlapping items when the group or layer has opacity.**
这是 5 条注意事项中最容易造成“视觉不一致”的一条,也是设计师与开发最容易争论的点。在 After Effects 中,你看到的是对整个图层/组施加透明度后的叠加结果;而 Lottie 的渲染模型是把不透明度(Opacity)下推到组内的每个独立元素(元素级 alpha),再逐个绘制叠加。
数学上两者并不等价:对整组先统一降低 alpha 再叠加,与组内每个元素各自带 alpha 叠加,重叠区域的混合颜色会不同。因此当图层/组内存在相互重叠的元素时,Android 上渲染出的颜色与 AE 预览会有肉眼可见的差异。
源码中的透明度计算印证了“逐层累积、逐元素应用”的模型:
- BaseLayer.java 中,图层最终 alpha 由父层透明度与自身透明度逐级相乘得到:
alpha = (parentAlpha / 255f * (opacity / 100f)) * 255,其中opacity来自图层变换(Transform)的透明度动画。 - 而组/形状内部每个内容元素在绘制时又各自携带自己的 alpha 值,最终呈现的是“元素独立透明度”叠加后的结果。
给设计师的落地建议:
- 若组/图层要整体做透明度动画,且组内元素互不重叠,通常不会有明显差异;
- 若组内元素互相重叠,应把透明度改为施加在**最外层的合成/预合成(Pre-comp)**上,或接受差异并手动微调颜色;
- 导出前务必在真机上与 AE 预览对比,把差异控制在验收标准之内。
七、如何把“规范违反”变成“可发现的问题”:利用警告机制
上面 4 处与规范相关的冲突(表达式、Illustrator 图层等)在源码中都会触发composition.addWarning(...)(警告的集合入口见 LottieComposition.java 的addWarning方法)。这意味着工程师可以在 Android 端程序化地发现设计师导出的 JSON 是否踩了红线:
- 加载完成后遍历
LottieComposition.getWarnings(); - 在开发/测试构建中把警告列表输出到日志或 UI(示例工程 sample 中就包含展示警告列表的底部面板相关实现,参考
bottom_sheet_warnings.xml布局),在动画上线前拦截不兼容问题; - 结合 snapshot-tests 下的快照测试资产(如
Tests/目录中各类 JSON),把设计师导出物纳入自动化回归,比对渲染截图,及时发现透明度叠加、蒙版表现等视觉偏差。
八、小结:设计师导出的最终自检清单
综合 DESIGNER_NOTES.md 与仓库实现,一份可贴在工位上的导出前自检清单如下:
| 检查项 | 规范要求 | 违反后果(源码/渲染层) |
|---|---|---|
| 表达式 | 不依赖表达式,烘焙为关键帧 | 属性被跳过,动画丢失,解析时产生警告(AnimatablePathValueParser.java、KeyframesParser.java) |
| 文本图层 | 转形状图层或随包提供字体 | 字形缺失、排版走样(依赖字体资源,见 TextLayer.java) |
| Illustrator 图层 | 转换为形状图层 | 导出为位图,包体增大、缩放失真(LayerParser.java 产生警告) |
| 蒙版/蒙板范围 | 裁剪内容尽量小 | 离屏渲染区域变大,帧率下降(BaseLayer.java 的离屏合成路径) |
| 组/图层透明度 | 重叠元素避免整体降透明度 | 重叠区颜色与 AE 预览不一致(透明度逐级相乘,见 BaseLayer.java) |
Lottie 的价值在于“设计师做完即上线”,但这份自由的前提是严格遵守 DESIGNER_NOTES.md 中这 5 条约束。把它们固化进团队的动画交付规范,配合代码层的警告检查与快照回归,就能在动画上线前把绝大多数兼容性与性能问题挡在门外。
- UI组件
- 移动开发
- 图形学
【免费下载链接】lottie-android
Render After Effects animations natively on Android and iOS, Web, and React Native
相关推荐
Lottie Web(lottie-web)实战指南:从 After Effects 导出到 SVG/Canvas 网页动画渲染
Lottie Web(lottie web)实战指南:从 After Effects 导出到 SVG/Canvas 网页动画渲染 Lottie 是一套解析 Ad
前端图形学Lottie-iOS: 原生渲染After Effects矢量动画的iOS库
Lottie iOS: 原生渲染After Effects矢量动画的iOS库 项目介绍 Lottie是一款跨平台的库,用于在iOS、macOS、tvOS、vis
图形学移动开发深入解析Lottie React Native:从After Effects到原生渲染的完整流程
深入解析Lottie React Native:从After Effects到原生渲染的完整流程 Lottie React Native是一个革命性的动画解决方
移动开发UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考