Lottie动画的优劣及原理

这篇具有很好参考价值的文章主要介绍了Lottie动画的优劣及原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

Lottie是目前应用十分广泛的动画框架。在周会汇报的时候,老板问能不能对Lottie进行优化,于是就有了下文对Lottie原理的研究。毕竟要进行优化,首先要深入了解原理嘛。

Lottie实现

  • Lottie通过读取json文件信息实现动画效果。
  • json信息包括json整体结构、图片资源、图层信息等,这些属性阐述了动画该做什么、该怎么做。
  • json文件解析:
    Lottie动画的优劣及原理

Lottie动画总体实现原理

Lottie动画的优劣及原理

  • Lottie 先将动画 JSON 文件转换为 LottieComposition 数据对象。
  • 继承 ImageView 的LottieAnimationView 将数据对象 LottieComposition 和渲染能力委托给
    LottieDrawable 处理。
  • 在 LottieDrawable 中会将数据对象 LottieComposition 组建为具有 draw 能力的
    BaseLayer
  • 并在 LottieAnimationView 需要绘制时,调用自己和各个层级BaseLayer 的渲染,从而达到动画效果。

下文将把Lottie原理细分为适配绘制动画原理,并辅以源代码进行阐述。

适配原理

  • 对于普通图片,可能会需要2x,3x多份图片资源进行手机适配。
  • 而Lottie本身已经自带了适配的功能:解析json文件时,读取动画的宽、高之后,会乘以手机的密度。在使用的时候判断Lottie动画适配后的宽高是否大于手机实际宽高,如果大于,Lottie会进行缩放。

绘制原理

  1. 获取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);
  1. 从源码可以看到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);
}
  1. 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);
    }
  1. 构造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的关系。
Lottie动画的优劣及原理
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;
   }
 }
  1. 如果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);
    }
  }

//BaseLayer
  void setProgress(@FloatRange(from = 0f, to = 1f) float progress) {
    //...
    for (int i = 0; i < animations.size(); i++) {
      animations.get(i).setProgress(progress);
    }
  }

//BaseKeyframeAnimation
  void 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();
  }

//BaseLayer
  private 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的计算过程。
Lottie动画的优劣及原理

  • 如果没有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.LottieAnimationView
        android:id="@+id/animation_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        app:lottie_rawRes="@raw/hello_world"
        // or
        app:lottie_fileName="hello_world.json"

        app:lottie_loop="true"
        app:lottie_autoPlay="true" />

xml文件中Lottie各属性
Lottie动画的优劣及原理
代码中使用Lottie

LottieAnimationView animationView = ...

animationView.setAnimation(R.raw.hello_world);
// or
animationView.setAnimation(R.raw.hello_world.json);

animationView.playAnimation();

代码中Lottie各属性
Lottie动画的优劣及原理

Lottie动态配置

lottieAnimationView.setAnimationFromUrl(url); 
lottieAnimationView.playAnimation();

更多技术文章欢迎关注公众号度熊君。
文章来源地址https://www.toymoban.com/news/detail-446209.html

到了这里,关于Lottie动画的优劣及原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android Lottie加载gson文件动画

    一:Lottie的使用 在你工程的build.gradle文件里添加如下配置 二:布局文件直接引入LottieAnimationView 例如:文件放置目录 如此,动画就能跑起来了: 1.lottie_fileName:在app/src/main/assets目录下的动画json文件名。 2.lottie_loop:动画是否循环播放,默认不循环播放。 3.lottie_autoPlay:动画

    2024年02月11日
    浏览(53)
  • android studio启动页面动画Lottie

    1.在build.gradle(app)中加入依赖 implementation\\\'com.airbnb.android:lottie:3.7.0\\\'  2.在Java包下新建活动  3.在res下创建raw包  

    2023年04月08日
    浏览(50)
  • vue3+vite中使用Lottie动画

    Lottie通过读取json文件信息实现动画效果   官方文档 Lottie官网 lottie库有众多动画 选择下载Lottie JSON到项目中 安装Lottie包 pnpm add lottie-web 模板创建  引入lottie-web以及动画json文件 import lottie from \\\'lottie-web\\\'; import transformJson from \\\"@/assets/json/playLottie.json\\\" js   动画生成!!! 

    2024年02月07日
    浏览(36)
  • 微信小程序通过lottie库实现json动画

    通过npm安装Lottie库(注意微信小程序使用lottie-miniprogram,vue项目使用 lottie-web) 把ui提供的json文件动画改成js文件并通过module.exports导出文件 在页面wxml文件创建一个canvas标签来存放动画(注意这里canvas需要包裹在view标签中并设置 style=\\\"width: 100%;height: 100%;) 在页面ts文件中使用

    2024年02月11日
    浏览(41)
  • 微信小程序使用lottie-miniprogram插件。显示json格式的动画,手机上锯齿模糊问题

    https://github.com/wechat-miniprogram/lottie-miniprogram 使用办法 通过 npm 安装: 传入 canvas 对象用于适配

    2024年02月11日
    浏览(57)
  • 安卓之DocumentsProvider应用场景以及优劣分析

    本文深入探讨了安卓 DocumentsProvider 的应用场景,分析了其优势与不足,并提供了简单的代码实现。 DocumentsProvider 是安卓系统中用于文件存储与访问的关键组件,为应用开发者提供了强大的文件管理能力。 DocumentsProvider 是安卓系统中的一个组件,允许应用以统一的方式访问和

    2024年02月04日
    浏览(41)
  • 安卓之缓存的应用场景以及各种技术优劣分析

            本文主要探讨了安卓开发中的缓存技术及其应用场景,通过分析几种常见的缓存技术,包括内存缓存、磁盘缓存和网络缓存,阐述了它们的优点和缺点。此外,本文还提供了相应的代码示例,以帮助读者更好地理解这些缓存技术的实现方式。         在当今的

    2024年02月01日
    浏览(41)
  • Webpack5入门到原理1:前言

    开发时,我们会使用框架(React、Vue),ES6 模块化语法,Less/Sass 等 css 预处理器等语法进行开发。 这样的代码要想在浏览器运行必须经过编译成浏览器能识别的 JS、Css 等语法,才能运行。 所以我们需要打包工具帮我们做完这些事。 除此之外,打包工具还能压缩代码、做兼容

    2024年01月20日
    浏览(51)
  • 安卓之图表库的应用场景、技术实现及其优劣分析

            在移动应用开发中,数据可视化对于提供直观信息、帮助用户理解数据至关重要。安卓平台上的图表库为开发者提供了一系列工具和组件,使他们能够轻松地创建各种类型的图表,如线型图、柱状图、蜡烛图、气泡图、饼状图、雷达图以及散点图等。本文将深入探

    2024年01月19日
    浏览(50)
  • 安卓之文本转视频的应用场景以及技术优劣分析

            随着科技的进步,文本与视频这两种信息传递形式之间的界限正在逐渐模糊。特别是在安卓平台上,将文本转换为视频的功能已经成为一种重要的应用场景。本文将深入探讨这一功能的应用场景、涉及的关键技术,以及其优劣分析。 1.1、 内容创作与分享      

    2024年01月22日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包