Lottie动画的优劣及原理
前言
Lottie是目前应用十分广泛的动画框架。在周会汇报的时候,老板问能不能对Lottie进行优化,于是就有了下文对Lottie原理的研究。毕竟要进行优化,首先要深入了解原理嘛。
Lottie实现
- Lottie通过读取json文件信息实现动画效果。
- json信息包括json整体结构、图片资源、图层信息等,这些属性阐述了动画该做什么、该怎么做。
- json文件解析:
Lottie动画总体实现原理
- Lottie 先将动画 JSON 文件转换为 LottieComposition 数据对象。
- 继承 ImageView 的LottieAnimationView 将数据对象 LottieComposition 和渲染能力委托给
LottieDrawable 处理。 - 在 LottieDrawable 中会将数据对象 LottieComposition 组建为具有 draw 能力的
BaseLayer。 - 并在 LottieAnimationView 需要绘制时,调用自己和各个层级BaseLayer 的渲染,从而达到动画效果。
下文将把Lottie原理细分为适配、绘制、动画原理,并辅以源代码进行阐述。
适配原理
- 对于普通图片,可能会需要2x,3x多份图片资源进行手机适配。
- 而Lottie本身已经自带了适配的功能:解析json文件时,读取动画的宽、高之后,会乘以手机的密度。在使用的时候判断Lottie动画适配后的宽高是否大于手机实际宽高,如果大于,Lottie会进行缩放。
绘制原理
- 获取LottieComposition数据对象
//Raw 文件加载
LottieComposition.Factory.fromRawFile(this,R.raw.data, compositionListener);
//asset 文件加载LottieComposition.Factory.fromAssetFileName(this, "data.json", compositionListener);
//自定义文件目录加载LottieComposition.Factory.fromInputStream(new FileInputStream("/sdcard/data/data.json"), compositionListener);
- 从源码可以看到LottieComposition被传给了LottieDrawer。
public void setComposition(@NonNull LottieComposition composition){if (L.DBG) {Log.v(TAG, "Set Composition \n" + composition);}lottieDrawable.setCallback(this);this.composition = composition;boolean isNewComposition = lottieDrawable.setComposition(composition);
}
- LottieDrawable通过buildComposition方法构造最外层的CompositionLayer。
public boolean setComposition(LottieComposition composition) {if (this.composition == composition) {return false;}clearComposition();this.composition = composition;buildCompositionLayer();animator.setComposition(composition);// ......}private void buildCompositionLayer() {compositionLayer = new CompositionLayer(this, LayerParser.parse(composition), composition.getLayers(), composition);}
- 构造CompositionLayer时,遍历LottieComposition数据对象中所有的Layer数据,并将其转换为BaseLayer图层对象。
public CompositionLayer(LottieDrawable lottieDrawable, Layer layerModel, List<Layer> layerModels,LottieComposition composition) {super(lottieDrawable, layerModel);LongSparseArray<BaseLayer> layerMap = new LongSparseArray<>(composition.getLayers().size());BaseLayer mattedLayer = null;for (int i = layerModels.size() - 1; i >= 0; i--) {Layer lm = layerModels.get(i);BaseLayer layer = BaseLayer.forModel(lm, lottieDrawable, composition);}
}
CompositionLayer与其他BaseLayer的关系类似于ViewGroup与View的关系。
5. BaseLayer 的 draw 绘制过程中,会调用抽象方法 drawLayer,各个继承的子类会具体实现。
@SuppressLint("WrongConstant")
@Override
public void draw(Canvas canvas, Matrix parentMatrix, int parentAlpha){if (!hasMatteOnThisLayer() && !hasMasksOnThisLayer()) {matrix.preConcat(transform.getMatrix());L.beginSection("Layer#drawLayer");drawLayer(canvas, matrix, alpha);L.endSection("Layer#drawLayer");recordRenderTime(L.endSection(drawTraceName));return;}}
- 如果Composition包含多个子图层,会遍历子图层,调用各自的draw方法进行绘制。
@Override
void drawLayer(Canvas canvas, Matrix parentMatrix, int parentAlpha){L.beginSection("CompositionLayer#draw");canvas.save();newClipRect.set(0, 0, layerModel.getPreCompWidth(), layerModel.getPreCompHeight());parentMatrix.mapRect(newClipRect);for (int i = layers.size() - 1; i >= 0 ; i--) {boolean nonEmptyClip = true;if (!newClipRect.isEmpty()) {nonEmptyClip = canvas.clipRect(newClipRect);}if (nonEmptyClip) {BaseLayer layer = layers.get(i);layer.draw(canvas, parentMatrix, parentAlpha);}}canvas.restore();L.endSection("CompositionLayer#draw");
}
动画原理
- 使用LottieAnimationView.playAnimaiton方法可以执行动画。
- 在animator执行过程中会逐层回调setprogress方法。
- 最终触发lottieDrawable的invalidateSelf方法,使lottieDrawable重新绘制。
- 这样随着animator的进行,lottieDrawable重新绘制,最终形成完整的动画。源码如下。
//LottieDrawable public void setProgress(@FloatRange(from = 0f, to = 1f) float progress) {this.progress = progress;if (compositionLayer != null) {compositionLayer.setProgress(progress);}}//CompositionLayer@Override public void setProgress(@FloatRange(from = 0f, to = 1f) float progress) {super.setProgress(progress);progress -= layerModel.getStartProgress();for (int i = layers.size() - 1; i >= 0; i--) {layers.get(i).setProgress(progress);}}//BaseLayervoid setProgress(@FloatRange(from = 0f, to = 1f) float progress) {//...for (int i = 0; i < animations.size(); i++) {animations.get(i).setProgress(progress);}}//BaseKeyframeAnimationvoid setProgress(@FloatRange(from = 0f, to = 1f) float progress) {if (progress < getStartDelayProgress()) {progress = 0f;} else if (progress > getEndProgress()) {progress = 1f;}if (progress == this.progress) {return;}this.progress = progress;for (int i = 0; i < listeners.size(); i++) {listeners.get(i).onValueChanged();}}//BaseLayer@Override public void onValueChanged() {invalidateSelf();}//BaseLayerprivate void invalidateSelf() {lottieDrawable.invalidateSelf();}
Lottie的优劣
优点:
- 支持跨平台,开发成本较低,一套Lottie动画可以在Android/IOS/Web多端使用。
- 性能好,端上除了解析json,基本没有其他耗性能的操作;并且相比于需要存储较多图片的帧动画,Lottie可以节省比较多的内存空间。
- 可以从服务端配置URL实现,不需要APP发版就可以实现更新。
不足点:
- Lottie动画不能进行交互。
- Lottie动画端上也无法进行编辑。
- Lottie不支持加载文字。
- Lottie不支持压缩位图,如果使用png等位图,需要自行在tiny等压缩平台进行图片压缩、降低包体积。
- Lottie存在mask、matters 时,性能会受到较大影响。
mask(掩膜):
- 用选定的图形或物体,对要处理的图像进行遮挡,控制图像的处理区域或处理过程。
Matte(前景蒙版):
- 前背景分离的结果,是一个灰度图,灰度图上的每个像素点的灰度值代表原始图像每个像素属于前景的程度。
- 白色代表某一个像素属于前景。
- 黑色代表某个像素属于背景。
Mask和Matte的区别:
- Mask是Matte的一种特例。
- Mask只有两种透明度,1和0,即完全透明和完全不透明。Mask是为了去除合成的锯齿而设计,不过锯齿没了,合成痕迹明显,显得不真实。
- Matte有很多层次的透明度。图像中每个像素都有自己的透明度,这些像素的透明度可以合成、融合,使图片看起来真实自然。
可以在源码中查看Mask、Matte的计算过程。
- 如果没有Mask或Matte,直接调用drawLayer返回。
- 如果存在Mask或Matte,需要先saveLayer,再调用drawLayer返回。
- saveLayer是一个耗时的操作,需要先分配、绘制一个offscreen的缓冲区,这增加了渲染的时间。
Lottie的使用
加载动画资源的方式
- src/main/res/raw 中的 json 动画。
- src/main/assets 中的 json 文件。
- src/main/assets 中的 zip 文件。
- json 或 zip 文件的 Url。
- json 或 zip 文件的 InputStream。
- json 字符串。
xml文件使用Lottie
<com.airbnb.lottie.LottieAnimationViewandroid:id="@+id/animation_view"android:layout_width="wrap_content"android:layout_height="wrap_content"app:lottie_rawRes="@raw/hello_world"// orapp:lottie_fileName="hello_world.json"app:lottie_loop="true"app:lottie_autoPlay="true" />
xml文件中Lottie各属性
代码中使用Lottie
LottieAnimationView animationView = ...animationView.setAnimation(R.raw.hello_world);
// or
animationView.setAnimation(R.raw.hello_world.json);animationView.playAnimation();
代码中Lottie各属性
Lottie动态配置
lottieAnimationView.setAnimationFromUrl(url);
lottieAnimationView.playAnimation();
更多技术文章欢迎关注公众号度熊君。
Lottie动画的优劣及原理相关推荐
- lottie 动画_使用After Effects和Lottie制作网络动画而不会损失质量
lottie 动画 A quick getting started guide 快速入门指南 I recently took on a project where the team wanted to ...
- 在vue里使用Lottie动画(实现 json 格式的动画)
一.Lottie简介与作用 Lottie是一个库,可以解析使用AE制作的动画(需要用bodymovin导出为json格式),支持web.ios.android和react native.在前端使用,l ...
- Lottie动画概述
这里东Copy,西Copy一下 Lottie 的特点. 学习的blog有:Lottie调研小结 Lottie的基本用法及原理分析 添加链接描述 Lottie的概念 原生的动画效果有时候写起来会非常的复 ...
- 程序员也想改 Lottie 动画?是的!
一.前言 Hi,大家好,我是承香墨影! Lottie 是 Airbnb 开源的一套跨平台的完整的动画效果解决方案,用过都说好.完全解耦开发人员和设计师,让设计师设计的动画,在程序中无缝还原,真是一旦拿 ...
- android jason动画,Android 动画之Lottie动画使用
Android 动画之Lottie动画使用 一:简介 Lottie是Airbnb开源的一套跨平台的完整解决方案,设计师只需要使用After Effects(简称AE)设计动画之后,使用Lottic提供 ...
- flutter 动画json_Flutter 50: 图解动画小插曲之 Lottie 动画
和尚在一年前整理过一点 Lottie 在 Android 中的应用,现在 Flutter 也有相关的插件帮助我们快速简单的应用场景复杂的 Lottie 动画: 和尚在官网查询之后发现官网推荐了两个开源 ...
- maya扇子动画_MAYA制作动画的十大原理!
什么是三维动画? 三维动画又称3D动画,主要应用在影视领域,比如大家都很熟悉的动画作品,2015年7月份上映的<大圣归来>和2019年上映的<哪吒>再次掀起了国内制作动漫的热潮 ...
- 一个动画看懂网络原理之CSMA/CD的工作原理
一个动画看懂网络原理之CSMA/CD的工作原理 CSMA/CD协议是以太网传输中的一个重要协议,由于线路中同一时间只能允许一台电脑发送信息,否则各计算机之间就会产生干扰,为了解决这个问题,采用了CSM ...
- 在VUE中使用Lottie动画
Lottie简介 官方介绍:Lottie is a mobile library for Web, and iOS that parses Adobe After Effects animations ...
- 计算机网络原理fin,一个动画看懂网络原理之TCP建立和释放过程
一个动画看懂网络原理之TCP建立和释放过程 一.TCP的概念 TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议.T ...
最新文章
- C++ map的使用
- 赶上直播电商、在线教育、小程序直播的风口 腾讯音视频解决方案助力
- 启明云端分享|乐鑫 ESP-NOW 无线通信方案主要特点、应用以及NOW一对一模式下通信速率
- 二十四、创建Node项目,深入Nodejs
- 为什么最近的食盐用量增加了?
- 前端学习(2682):重读vue电商网站2之前台启动
- phpmyadmin 导出mysql_PhpMyAdmin创建/导入/导出MySQL数据库教程[图文]
- linux内核通俗理解,简洁明了!高手带你理解ARM-Linux的启动过程
- ShoeBox一个超级好用的图片切割工具
- matlab 自带定积分,Matlab怎么计算定积分,划重点了
- 数据挖掘实验(三)Matlab初步实现ID3算法【决策树根节点选择】
- 计算机硬件的五大逻辑部分,计算机的硬件系统由五大部分组成(计算机由几部分组成)...
- SAP固定资产模块的表
- maya cmds 笔记_1
- 【Windows7系统装什么浏览器好用】
- VScode安装及个性化插件设置
- 1050: 平方和与立方和
- 继续谈谈从Rxjava迁移到Flow的背压策略
- Oracle体系结构VI
- 记一次java面试(小黑鱼)