Lottie 动画在项目中的使用总结

Posted 小羊子说

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lottie 动画在项目中的使用总结相关的知识,希望对你有一定的参考价值。

文章目录

Lottie 动画在项目中的使用总结

1.背景

基于 lottie 动画高频使用用法,总结 lottie 动画在项目中的使用技巧及注意事项,便于以后在项目中处理类似需求快速检索入运用,后期会不定期完善,欢迎补充及指正不足之处。

2. Lottie 是什么?

Lottie 是一个同时支持 androidios 、React Native 、Web 和 Windows 设备的一个开源动画框架。

用户只要先用 Adobe After Effects 软件做出动画,再将动画文件通过 Bodymovin 导出为 json 文件,就可以通过 Lottie 来解析这些 json 文件实现动画了。

前端开发人员,只需要拿到 UI (动效)同学给的 json 文件 即可实现 动效的 百分之百的还原,简单高效。

3. Lottie 核心类

Lottie 提供一个 LottieAnimationView 给用户使用,而实际 Lottie 的核心是 LottieDrawable,它承载了所有的绘制工作,LottieAnimationView 则是对 LottieDrawable 的封装,再附加了一些例如解析的功能。

  • LottieComposition 是对应的 Model,承载所有信息。
  • CompositionLayer 是 layer 的集合。
  • ImageAssetBitmapManager 负责管理动画所需的图片资源。
  • LottieAnimationView 用户加载 Lottie 动画的默认和最简单的方式(直接使用)

4. 使用步骤

​ 开源地址:https://github.com/airbnb/lottie-android

  1. 添加依赖
dependencies 
  implementation 'com.airbnb.android:lottie:$lottieVersion'

截至目前,最新版本为:5.0.3

  1. 在布局 xml 中使用:
<com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lottieAnimationView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:lottie_fileName="hello-world.json"
        app:lottie_loop="true"
        app:lottie_rawRes="@raw/heart"
        app:lottie_imageAssetsFolder="images"
        app:lottie_autoPlay="true"

注意: 这里的 app:lottie_rawResapp:lottie_fileName 这两个属性是一样的。

上图 xml 里面的 @raw/heart是一个 json 文件,Lottie 是通过解析 json 文件去实现的。

LottieAnimationView animationView = ... 
animationView.setAnimation(R.raw.hello_world); 
// or 
animationView.setAnimation(R.raw.hello_world.json); 
animationView.playAnimation();
  1. 控制动画添加动画监听
lottieAnimationView.addAnimatorUpdateListener((animation) -> 
    // 动画状态监听回调
);
lottieAnimationView.playAnimation(); // 播放动画
...
if (lottieAnimationView.isAnimating())  // 动画正在运行

...
// progress 范围 0 ~ 1f,设置动画进度
lottieAnimationView.setProgress(0.5f);
...
// 自定义动画时长,此处利用 ValueAnimator 值动画来实时更新 AnimationView 的进度来达到控制动画时长。
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f)
    .setDuration(500);
animator.addUpdateListener(animation -> 
    lottieAnimationView.setProgress(animation.getAnimatedValue());
);
animator.start();  // 启动动画
...
lottieAnimationView.cancelAnimation();// 取消动画

因此,可以随意控制动画的时常,动画的播放进度,动画的各种状态等

  1. 常用方法:
方法功能
setAnimation(int)设置播放动画的 json 文件名称
setAnimation(int, CacheStrategy)设置播放动画的 json 文件资源和缓存策略
loop(boolean)设置动画是否循环(默认为false)
setRepeatMode(int)设置动画的重复模式(默认为restart)
setRepeatCount(int)设置动画的重复次数(默认为-1)
lottie_cacheStrategy设置动画的缓存策略(默认为weak)
lottie_colorFilter设置动画的着色颜色(优先级最低)
setScale(float)设置动画的比例(默认为1f)
setProgress(float)设置动画的播放进度
setImageAssetsFolder(String)设置动画依赖的图片资源文件地址
playAnimation()从头开始播放动画
pauseAnimation()暂停播放动画
resumeAnimation()继续从当前位置播放动画
cancelAnimation()取消播放动画
  1. 监听动画进度 [0,1]
   lottieAnimationView.addAnimatorUpdateListener(new ValueAnimator.AnimatorUpdateListener() 
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) 
            // 判断动画加载结束
            if (valueAnimator.getAnimatedFraction() == 1f) 
            
        
    );
  1. 循环/播放某个部分
lottieAnimationView.loop(true);
// 播放动画的某个部分
setMinFrame(...)
setMaxFrame(...)
setMinProgress(...)
setMaxProgress(...)
setMinAndMaxFrame(...)
setMinAndMaxProgress(...)
	4. 获取动画的时长
// 比如获取 UI 给的动画(lottie_count_down)素材时长  
val lottieComposition: LottieComposition = LottieCompositionFactory.fromRawResSync(
                context,
                R.raw.lottie_count_down
            ).value!!
Log.d(TAG, "lottieComposition.duration : $lottieComposition.duration ")  //  得到 6000ms

5. 使用注意事项

1. 控制 Lottie 动画执行的速度和时间

Lottie 动画,在导出成 JSON 之后,其实动画执行的速度和时长,都是已经固定了的。所以如果想要修改这两个参数,除了麻烦设计师使用 After Effects 重新修改之后再导出之外,还可以使用 ValueAniamtor 配合 setProgress() 方法来实现。

2. Lottie 的缓存策略

应用程序中可能会有一些经常使用的动画,比如加载动画等等。为了避免每次加载文件和发序列化的开销,你可以在你的动画上设置一个缓存策略。在 setAnimation() APIs都可以采用可选的第二个参数 CacheStrategy

在默认情况下,Lottie 将保存对动画的弱引用,这对于大多数情况来说应该足够了。

但是,如果确定某个动画肯定会经常使用,那么请将其缓存策略更改为 CacheStrategy.Strong
或者如果确定某个动画很大而且不会经常使用,把缓存策略改成 CacheStrategy.None

CacheStrategy 可以是NoneWeakStrong 三种形式来让 LottieAnimationView 对加载和解析动画的使用强或弱引用的方式。弱或强表示缓存中组合的 GC 引用强度。

6. 在项目中使用示例

需求场景:

用户播放倒计时视频时,根据播放的视频时长,同步实现水平进度条的圆滑动效。

开发实现思路:

​ 根据 UI 提供的动画(count_down.json)素材,计算不同时长的播放进度和速度。

   <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lottieCountDownTime"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center"
        app:lottie_fileName="lottie/count_down.json" />

关键思路

var mRestPastTime = 0L
private var countDownDuration: Long = 60L
fun start() 
        lottieCountDownTime.removeUpdateListener(mRestLottieAnimatorUpdateListener)
        lottieCountDownTime.cancelAnimation()
        mRestPastTime = 0L
        lottieCountDownTime.apply 
            val lottieComposition: LottieComposition = LottieCompositionFactory.fromRawResSync(
                context,
                R.raw.lottie_count_down
            ).value!!

            mRestLottieAnimatorUpdateListener = ValueAnimator.AnimatorUpdateListener  animation ->
                mRestPastTime = (countDownDuration * animation.animatedFraction).toLong()
                Log.d(TAG, "lottieComposition.duration : $lottieComposition.duration ")  // 5016ms
                countDownTime = countDownDuration - mRestPastTime
                val leftTime = (countDownTime / 1000).toString()
                Log.d(TAG, "leftTime:$leftTime ")  // 59 ~ 0 s
                setRestTimeText(countDownDuration - mRestPastTime, false)
                if (animation.animatedFraction >= 1) 
                    //播放结束处理
                
            
            setComposition(lottieComposition)
            progress = 0f
            //核心点:根据时长控制播放的进度
            speed = lottieComposition.duration / countDownDuration
            playAnimation()
            addAnimatorUpdateListener(mRestLottieAnimatorUpdateListener)
        
    

根据上述的使用示例,实现了 UI 给的水平进度条动效,非常圆滑的实现,并且滑动进度可以根据不同的时长来一一对应进度,在倒计时场景中,用户如果在播放视频时反复暂停和开启动操作,我们还得处理一下,进度和到计时状态同步的问题。此处用 lottie 动画来实现,只需要调用暂停(pauseAnimation)和恢复(resumeAnimation)即可。

其他实现思路1:

如果用属性动画来实现的话,可能会出现不同圆滑或有卡顿的情况。

用属性动画使用示例:

/**
     * 设置 ProgressBar 的进度(平滑的增长)
     * @param progressBar progressBar
     * @param progressTo 取值 0 - 100 在 10 倍的时间内平滑 效果更平滑
     */
    private fun setProgressSmooth(progressBar: ProgressBar, progressTo: Int) 
        val animator = ObjectAnimator.ofInt(
            progressBar, "progress",
            progressBar.progress,
            progressTo * 10
        )
        animator?.apply 
            duration = 300
            // 匀速绘制
            interpolator = LinearInterpolator()
            start()
        
    
  <ProgressBar
        android:id="@+id/countDownPb"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:max="1000"
        android:progressDrawable="@drawable/pb_pd_bg"
        tools:progress="500" />

注: 其中 pb_pd_bg.xml 中背景图的实现

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 进度条背景色 -->
    <item android:id="@android:id/background">
        <shape>
            <solid android:color="@color/black" />
        </shape>
    </item>
    <!--  第二进度条 -->
    <item android:id="@android:id/progress">
        <clip>
            <shape>
                <solid android:color="@color/blue" />
            </shape>
        </clip>
    </item>
</layer-list>

此处,android:max="1000"设置为 1000,这一点需要注意,平时开发中,我们一般设置为 100,这里是新的思路。在进度刷新时放大 10 倍,再结合属性动画的 LinearInterpolator特性,基本也能实现 水平圆滑的效果,不过在用户反复暂停或恢复倒计时,由于属性动画绘制时间duration的原因,不会立即停止,会有延迟暂停的卡顿感。

其他开发思路2:

可以用自定义 View 的思路实现,OnDraw 刷新时去同步进度。如何倒计时如果不想圆滑的效果,就 1s 更新 1次进度,

想圆滑进度的话,就 10ms 更新 1次。不过需要处理倒计时的暂停、恢复等业务逻辑。

综上,总结两种使用方法,在实际开发中,根据不同的使用场景选择。按目前的资源及动效要求,用 lottile 最简单最高效。

(后面有时间会进一步总结: 圆形倒计时中的圆滑进度实现 和实现倒计时的几种方式及场景运用)

7. FQA

一、如何快速预览设计师的 lottie 动画?

  1. UI 设计师提供 Demo 及 动效 Json+ html 文件 。点开HTML 文件即可预览。
  2. 在线预览 https://lottiefiles.com/private/animations(可以多个预览切换) 注册登录后,直接把 xx.json 动效文件拖到界面预览。部分白色的动效可能看不到,最好和设计师确定一下。
    2022.3.25 更新 直接在线预览 不用注册
    Lottie tools
    似乎比上面官方的好用。

二、 加载卡顿的问题

待补充

三、设置进度的问题

setMinAndMaxProgress(0.5f, 1f)

设置进度后:这里的 speed 会加速

四、 lottie 动画大小设置

由于 lottie 的底层为 ImageView,参考类似属性始可解决。

如,设置:

    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/countDownPb"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY"
        app:lottie_fileName="lottie/lottie_horizontal_progress.json" />

lottie_horizontal_progress.json中的大小可能不会铺满 match_parent,需要设置:android:scaleType="fitXY"

这里需要注意一下适配器,如果 UI 给的动效本身就是按固定尺寸来设计的,这里就不要设置这个属性了,否则会出现位置错乱的问题。

8. 未来方向

可能会用 PAG 取代 lottie

从解码渲染层面对比 PAG 与 lottie

9. 参考资料

lottie-android : github.com/airbnb/lott…

Introducing Lottie: medium.com/airbnb-engi…

design-lottie: airbnb.design/lottie/

bodymovin: github.com/bodymovin/b…

Animation: Jump-through: medium.com/google-deve…

以上是关于Lottie 动画在项目中的使用总结的主要内容,如果未能解决你的问题,请参考以下文章

[UWP]缓存Lottie动画帧

Lottie- 让Android动画实现更简单

Lottie- 让Android动画实现更简单

如果在Flutter Web项目中使用lottie动画

如果在Flutter Web项目中使用lottie动画

Lottie 动画在 SwiftUI 的最后一个 TabView 页面上消失