相关文章推荐
飞书中 Lottie 动画的应用

飞书中 Lottie 动画的应用

背景

飞书项目中 loading 常用的动画方案是 Gif 动画。

Gif 动画存在一定的问题,Gif 文件一般较大,且呈现的大小是固定的,无法缩放以匹配大屏幕和高密度屏幕,容易有锯齿,不能控制动画。

其他常用的动画方案:

Png 序列帧:合成的雪碧图文件大,且在不同屏幕分辨率下可能会失真

SVG 动画: 实现成本高,容易出现动画还原度低的情况

目前项目中需要一种更加简单、高效、性能好、还原度高的动画方案,设计同学正在推动 AE + bodymovin 导出动画配置的方案,经过调研发现 Lottie 动画是一种可行性较高的方案。

Lottie 简介

Lottie[1] 是 airbnb 开源的可应用于 Android[2] , iOS[3] , Web[4] , React Native[5] Windows[6] 动画库, 本质上是一套跨平台的动画解决方案。它提供了一套完整的从 AE 到各个终端的工具流,通过 AE 的 Bodymovin 插件将设计师做的动画导出成一套定义好的 json 文件,之后再通过 Lottie 各端的库就可以实现动画效果,动画还原度 100%, Lottie-web Example[7]


使用方法

lottie-web[8] 支持特性最多( airbnb.io/lottie/# ),可以实现较为复杂的动画,控制动画的播放,监听动画各个阶段的事件( github.com/airbnb/lotti )。

lottie-web[9] 的使用方法, 有三种渲染方式 svg, canvas, html, 一般常用 svg, canvas

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

react-lottie[10] 的使用方法(将 lottie-web[11] 封装成 React 组件)

import React from 'react'
import Lottie from 'react-lottie';
import * as animationData from './pinjump.json'
export default class LottieControl extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isStopped: false, isPaused: false};
  render() {
    const buttonStyle = {
      display: 'block',
      margin: '10px auto'
    const defaultOptions = {
      loop: true,
      autoplay: true,
      animationData: animationData,
      rendererSettings: {
        preserveAspectRatio: 'xMidYMid slice'
    return <div>
      <Lottie options={defaultOptions}
              height={400}
              width={400}
              isStopped={this.state.isStopped}
              isPaused={this.state.isPaused}/>
      <button style={buttonStyle} onClick={() => this.setState({isStopped: true})}>stop</button>
      <button style={buttonStyle} onClick={() => this.setState({isStopped: false})}>play</button>
      <button style={buttonStyle} onClick={() => this.setState({isPaused: !this.state.isPaused})}>pause</button>

控制动画播放的方法:

名称 描述

监听事件:

名称 描述

Lottie 动画性能测试

Lottie 局部加载动画, Gif 动画 与 Lottie 动画比较

Gif 动画性能


1,加载编译库文件的耗时(阻塞启动)

平均:25ms

2,lottie-web 文件本身的内存占用

shadow size: 136B Retained Size: 1209553B

3,执行时的耗时(体现到耗时上,CPU 采样会很不精准,阻塞业务逻辑,如启动 chat)

平均: 15.4ms

Lottie 动画性能

由上图可知,查看了 Gif 动画、Lottie 动画方案的 FPS、CPU 占用率、GPU 占用、Scripting、Rendering、Painting、内存的使用情况。

方案 大小 FPS CPU 占用率 GPU 占用 内存

通过以上数据分析,可知 Lottie 动画的配置文件较小,帧率较高,GPU 占用低,内存与 Gif 动画相差不大,性能较好。

Lottie 动画方案简单、高效、性能好,可以替代传统的 GIF 和帧动画,灵活利用好提供的属性和方法可以控制动画的播放。

注意事项

及时卸载 Lottie 动画组件

在不需要 Lottie 动画时,需要及时卸载 Lottie 动画组件

飞书出现过偶现 CPU 升高的异常案例,经过排查定位到是 Lottie 动画没有卸载引起的 CPU 升高。页面中已经没有动画,但 Lottie 一直在调用 requestAnimationFrame,导致在没有任何操作的情况下,CPU 占用升高至 2%-5% 左右,一般情况在没有任何操作的情况下,cpu 占用 0.1% ~0.2%。

Lottie 动画调用 react-lottie 组件,组件在 componentWillUnmount 时,会销毁该动画实例。

飞书中 CPU 升高的时候,发现 Lottie 动画中有动画实例尚未销毁,导致会不停的调用 requestAnimationFrame,导致异常的动画是局部加载动画。飞书中用到局部加载的动画的模块有主端(切换会话、联系人页面 、新添加的联系人、机器人、外部联系人、onCall、升级提示弹窗、添加联系搜索、发送云盘文件弹窗、Pin 列表、Docs Webview 加载动画、切换租户)、日历、应用中心等。

经过定位发现,应用中心里用到了局部加载动画, 在不需要动画的时候,没有卸载组件,只是通过 CSS 来隐藏了组件,导致没有销毁 Lottie 动画实例,requestAnimationFrame 会一直执行,代码如下:

// AppHome.js
 <div className={!isLoaded ? 'app-home-loadingImg' : 'display-none'}><PartialLoading /></div>

不需要 Lottie 动画的时候,卸载 Lottie 动画组件。

// AppHome.js
      !!isLoading && (
        <div className='app-home-loadingImg'>
          <PartialLoading />
 
推荐文章