Lottie库的使用调研(对比gif,序列帧,视频)

3,946 阅读7分钟

文档地址:Lottie Docs

通常复杂动画怎么处理?

使用GIF:

不足:

  • 文件占用空间大
  • 动画显示效果不佳
  • 会出现失真、模糊、出现锯齿情况
  • 掉帧严重
  • 需要适配分辨率
  • Android原生不支持GIF动画

使用SVG、canvas:

不足:

  • 实现、维护成本高
  • 复杂度过高会减慢渲染速度

使用png序列帧:

不足:

  • 需要大量图片
  • 增大项目体积
  • 在播放时占用大量内存,给项目增加负担
  • 需要适配分辨率

使用视频:

不足:

  • 占用空间大
  • 没有交互(只能等视频播放完毕才能交互)
  • 在播放时占用CPU内存较大
  • 体验不好

Lottie

Lottie是一个库,可以解析使用AE制作的动画(需要用bodymovie导出为json格式,UI关心),支持web、ios、android、flutter和react native。

research-lottie-1.png

在web端,可以使用 lottie-web 库解析导出的动画json文件,并将其以 SVG 或者 Canvas 的方式将动画绘制在我们的页面上,所以Web端的兼容性也等价于 SVGCanvas 的兼容性。

优点

  • 跨平台
  • 开发效率高 -> 代码实现简单,更换动画方便,易于调试和维护
  • 可以替代一些通过代码不好实现的动画效果
  • 数据源多样性 -> 可以从assets/sdcard,网络加载动画(JSON)资源,能做到不发版本,动态更新
  • 可网络加载,动态控制播放速度
  • 能够导出一份JSON文件,并且支持跨平台使用,android,ios,react native,Flutter通用。一次绘制、一次转换、随处可用
  • 能够100% 还原设计师给出的各种复杂动画效果
  • 占用空间更小(相对于其他方式)
  • 可手动设置进度,绑定手势,事件等
  • 不同的手机分辨率不需要适配
  • 针对复杂动画在低性能设备上的卡顿等性能问题提供了工程化的解决方案

不足

  • 对UI同学要求较高
  • 一些特殊场景难以胜任,比如蒙板和遮罩,对动画性能会有较大影响
  • 相对于属性动画,在展示大动画时帧率较低
  • lottie动画其实可以理解为svg/canvas动画,不能给已存在的html添加动画效果

使用场景

  • 不适用场景
    • 给 View 本身添加动画(如:从右下角到移动到页面中,并逐渐放大的过渡效果)
    • 动画中有动态内容(如:需要显示一个数量,多少来自数据库/网络)
  • 适用场景
    • 启动动画
    • 局部动画
    • 上下拉刷新动画
    • 加载动画
    • 提示动画
    • 按钮动画
    • 等等等。。。。。。

参考文档:github.com/airbnb/lott…

需要增大项目多少体积?

按最新版本 v5.10.2 分析如下:

research-lottie-2.png

动画原理

research-lottie-3.png

  • 一个完整动画View由很多个子Layer 组成,每个子Layer中主要通过shapes(形状),masks(蒙版),transform三大部分进行动画。
  • 通过读取Json文件 可以获取到每个子Layer 的shapes,masks,以及出现时间,消失时间,Transform 各个属性的关键帧数组
  • 动画通过给CompositionLayer (所有的子layer都添加在这个Layer 上)的 “CurrentFrame” 属性添加一个CABaseAnimation 来实现
  • 所有的子Layer根据CurrentFrame 属性的变化,根据Json中的关键帧数组计算出自己的当前状态进行显示。

JSON结构

{
  "fr": 30, // 帧率
  "ip": 0, // 起始关键帧
  "op": 20, // 结束关键帧
  "w": 150, // 视图宽
  "h": 130, // 视图高
  "assets": [], // 资源集合
  "layers": [{ // 图层
      "ty": 0, // 图层类型。
      "refId": "", // 引用的资源,图片/预合成层
      "ks": {}, // 变换。对应AE中的变换设置
      layer: [], // 该图层包含的子图层
      shapes: [], // 形状图层
      "w": 1334,
      "h": 750,
      "bm": 0
	}], // 图层集合
  "masker": [] // 蒙层集合
}

使用

  1. 安装NPM包(推荐)
  2. 可以直接在项目中引入静态 JS 文件
  3. CDN方式引入(不推荐)

Lottie Docs

配置

Lottie的主要配置参数如下:

参数说明数据格式默认值
container渲染动画的容器元素DOM Element-
path动画数据json文件的路径(和animationData参数二选一)string-
animationData动画数据(和path参数二选一)object-
renderer渲染方式, svg/canvas/html(轻量版仅svg渲染)string-
loop(可选)动画是否循环,为数字时即控制循环次数boolean/numberfalse
autoplay(可选)动画是否自动播放booleantrue
name(可选)自定义动画名称string-

方法

配置完动画后,我们可以拿到动画实例并通过实例方法进行控制:

  • play():播放动画,从当前停止帧开始
  • stop():终止动画,回到第0帧
  • pause():暂停动画,停止在当前帧
  • setLocationHref(href):href作为location.href,当你在Safari中遇到不带符号的掩码问题时,它非常有用。
  • setSpeed(speed):设置动画速度(1是正常速度)。speed参数为速度,number。
  • goToAndStop(value, isFrame):动画跨越到某进度并停止。value为进度数值,number;isFrame定义第一个参数(value)是基于时间的值还是基于帧的(默认为false)。
  • setDirection(direction):设置动画播放顺序(顺序播放/倒叙播放)。direction参数表明顺序,1为顺序,1为倒叙。
  • playSegments(segments, forceFlag):播放动画片段。segments参数可以包含两个将用作动画第一帧和最后一帧的数值,或者可以包含一系列数组,每个数组都有2个数值,array。forceFlag表示是否立即强制播放该片段,如果设置为false,它将等待当前段完成。如果为true,它将立即播放此片段,boolean。如animation.playSegments([10,20], false); // 播放完之前的片段,播放10-20帧animation.playSegments([[0,5],[10,18]], true); // 直接播放0-5帧和10-18帧
  • setSubframe(useSubFrames):useSubFrames参数如果为false,则将尊重原始的AE fps。如果为true,它将使用中间值在每个RequestAnimationFrame上更新。默认值为true, boolean。
  • destory():删除该动画,移除相应的元素标签等。在unmount的时候,需要调用该方法
  • getDuration(inFrames),获取动画持续时间。inFrames参数为true,则返回以帧为单位的持续时间;如果为false,则返回以秒为单位的持续时间。

事件

在使用中可能也需要监听一些事件:

  • complete: 播放完成(循环播放下不会触发)
  • loopComplete: 当前循环下播放(循环播放/非循环播放)结束时触发
  • enterFrame: 每进入一帧就会触发,播放时每一帧都会触发一次,stop方法也会触发
  • segmentStart: 播放指定片段时触发,playSegments、resetSegments等方法刚开始播放指定片段时会发出,如果playSegments播放多个片段,多个片段最开始都会触发。
  • data_ready: 动画数据json文件加载完毕触发
  • data_fail:动画数据json文件加载失败触发
  • loaded_images:当所有图片加载成功/失败时触发
  • DOMLoaded: 动画相关的dom已经被添加到html后触发
  • destroy: 将在动画删除时触发

使用如:

// 上例的animation实例
animation.addEventListener('enterFrame', function () {
  console.log('lottie');
});

注意事项/常见问题

Lottie不支持表达式,特效,mask蒙版等功能,如果用了,要不是JSON数据导出失败,要不就是在Web上显示不出来,或者和预期显示不一样

使用官方例子(如下代码)可能会报一个错:

Uncaught TypeError: params.path.lastIndexOf is not a function

原因是使用path,页面会通过一个 http 请求获取 json

lottie.loadAnimation({
  container: element, // the dom element that will contain the animation
  renderer: 'svg',
  loop: true,
  autoplay: true,
  path: 'data.json' // the path to the animation json
});

只需把上面的 path替换成 animationData即可,animationData使用的是本地的JSON文件

Issues地址:github.com/airbnb/lott…

#_#