美文网首页交互动画(代码篇)
Android Lottie动画使用

Android Lottie动画使用

作者: 请叫我果爸 | 来源:发表于2018-08-13 11:00 被阅读0次

    一、简介

    Lottie 是Airbnb开源的一个面向 iOS、Android、React Native 的动画库,能分析 Adobe After Effects 导出的动画,并且能让原生 App 像使用静态素材一样使用这些动画,完美实现动画效果。

    二、Lottie动画文件制作

    1.让设计师使用Adobe 的 After Effects(简称 AE)工具(美工一般都会这个)制作这个动画。

    2.在AE中安装一个叫做Bodymovin的插件。 下载 bodymovin,解压缩后只需要\build\extension\bodymovin.zxp这个档案就可以

    3.手动安装plugin,以windows系统而言,要先下载 **ExMan Command Line tool **并解压缩。 再来把下载的bodymovin压缩后的 bodymovin-master\build\extension 目录下的bodymovin.zxp 这个档案复制进去同一个资料夹。

    4.去找cmd,并以系统管理员身分执行。

    5.打“cd C:/ExManCmd_win 所在的路径 “,进入ExManCmd的资料夹中

    6.接着打 ExManCmd.exe /install bodymovin.zxp 就完成了

    7.再来进入AE 后,可以在windows/extentions/bodymovin 找到插件,开启后按下Render 就完成了。 重点来了,这时会在你选的Destination Folder目录中生成一个json格式的文件,这个 json 文件描述了该动画的一些关键点的坐标以及运动轨迹。

    三、如何使用Lottie

    Lottie支持多平台,使用同一个JSON动画文件,可在不同平台实现相同的效果。支持Android,ios,前段。

    1.依赖

    在项目的 build.gradle 文件添加依赖

    dependencies {    compile 'com.airbnb.android:lottie:2.1.0'}
    

    2.动画文件

    第一种方法,将我们所需要的动画文件loading.json保存在app/src/main/assets文件里。

    第二种方法,网络上AE生成的动画文件。(网络链接)

    3.使用

    在布局文件中使用

    <com.airbnb.lottie.LottieAnimationView
            android:id="@+id/animation_view"
            android:layout_width="400dp"
            android:layout_height="400dp"
            app:lottie_fileName="loading.json"
            app:lottie_loop="true"
            app:lottie_autoPlay="true"/>
    

    使用网络加载AE生成的动画文件json

    private void loadUrl(String url) {
        client.newCall(request).enqueue(new Callback() {
            @Override
             public void onFailure(Call call, IOException e) {
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    try {
                        JSONObject json = new JSONObject(response.body().string());
                        LottieComposition.Factory                            .fromJson(getResources(), json, new OnCompositionLoadedListener() {
                                    @Override
                                    public void onCompositionLoaded(LottieComposition composition) {
                                        setComposition(composition);
                                    }
                                });
                    } catch (JSONException e) {
                    }
                }
            }
        });
    }
    private  void setComposition(LottieComposition composition){
        animation_view.setProgress(0);
        animation_view.loop(true);
        animation_view.setComposition(composition);
        animation_view.playAnimation();
    }
    

    四、Lottie实现原理

    设计师把一张复杂的图片使用多个图层来表示,每个图层展示一部分内容,图层中的内容也可以拆分为多个元素。拆分元素之后,根据动画需求,可以单独对图层或者图层中的元素做平移、旋转、收缩等动画。

    Lottie的使用的资源是需要先通过bodymovin( bodymovin 插件本身是用于网页上呈现各种AE效果的一个开源库)将 Adobe After Effects (AE)生成的aep动画工程文件转换为通用的json格式描述文件。Lottie则负责解析动画的数据,计算每个动画在某个时间点的状态,准确地绘制到屏幕上。

    Lottie主要类图:

    Lottie对外通过控件LottieAnimationView暴露接口,控制动画。

    LottieAnimationView继承自ImageView,通过当前时间绘制canvas显示到界面上。这里有两个关键类:LottieComposition 负责解析json描述文件,把json内容转成Java数据对象;LottieDrawable负责绘制,把LottieComposition转成的数据对象绘制成drawable显示到View上。顺序如下:

    解析json外部结构

    LottieComposition封装整个动画的信息,包括动画大小,动画时长,帧率,用到的图片,字体,图层等等。

    {
        "v": "4.6.0",               //bodymovin的版本
        "fr": 29.9700012207031,     //帧率
        "ip": 0,                    //起始关键帧
        "op": 141.000005743048,     //结束关键帧
        "w": 800,                   //动画宽度
        "h": 800,                   //动画高度
        "ddd": 0,
        "assets": [...]             //资源信息
        "layers": [...]             //图层信息
    }
    

    解析图片资源

    "assets": [                 //资源信息
        {                       //第一张图片
            "id": "image_0",    //图片id
            "w": 58,            //图片宽度
            "h": 31,            //图片高度
            "u": "images/",     //图片路径
            "p": "img_0.png"    //图片名称    
        },    
        {...}                   //第n张图片
    ]
    

    解析图层

    "layers": [                 //图层信息
        {                       //第一层动画
            "ddd": 0,
            "ind": 0,           //layer id 图层 id
            "ty": 4,            //图层类型
            "nm": "center_circle",
            "ks": {...},        //动画
            "ao": 0,
            "shapes": [...],
            "ip": 0,            //inFrame 该图层起始关键帧
            "op": 90,           //outFrame 该图层结束关键帧
            "st": 0,            //startFrame 开始
            "bm": 0,
             "sr": 1
        },
        {...}                   //第n层动画
    ]
    

    如何动起来

    时序图

    利用属性动画控制进度,每次进度改变通知到每一层,触发LottieAnimationView重绘。

    代码如下:

    public LottieDrawable() {    
            animator.setRepeatCount(0);    
            animator.setInterpolator(new LinearInterpolator());    
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                  
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                            if (systemAnimationsAreDisabled) {
                                    animator.cancel();
                                    setProgress(1f);
                } else {
                    setProgress((float) animation.getAnimatedValue());
                }
            }
        });
    }
    

    通过CompositionLayer把进度传递到各个图层

    @Override
    public void setProgress(@FloatRange(from = 0f, to = 1f) float progress) {
        super.setProgress(progress);
        if (timeRemapping != null) {
            long duration = lottieDrawable.getComposition().getDuration();
            long remappedTime = (long) (timeRemapping.getValue() * 1000);
            progress = remappedTime / (float) duration;
        }
        if (layerModel.getTimeStretch() != 0) {
            progress /= layerModel.getTimeStretch();
        }
        progress -= layerModel.getStartProgress();
        for (int i = layers.size() - 1; i >= 0; i--) {
            layers.get(i).setProgress(progress);
        }
    }
    

    通知进度改变

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

    最终回调到LottieAnimationView的invalidateDrawable

    @Overridepublic void invalidateDrawable(@NonNull Drawable dr) {
        if (getDrawable() == lottieDrawable) {
          // We always want to invalidate the root drawable so it redraws the whole drawable.
          // Eventually it would be great to be able to invalidate just the changed region.
            super.invalidateDrawable(lottieDrawable);
        } else {
          // Otherwise work as regular ImageView
            super.invalidateDrawable(dr);
        }
    }
    

    最后触发LottieDrawable重绘

    @Overridepublic void draw(@NonNull Canvas canvas) {
        ...
        matrix.reset();
        matrix.preScale(scale, scale);
        compositionLayer.draw(canvas, matrix, alpha);
        //这里会调用所有layer的绘制方法
        if (hasExtraScale) {
            canvas.restore();
        }
    }
    

    五、性能

    1.官方说明

    如果没有mask和mattes,那么性能和内存非常好,没有bitmap创建,大部分操作都是简单的cavas绘制。

    如果存在mattes,将会创建2~3个bitmap。bitmap在动画加载到window时被创建,被window删除时回收。所以不宜在RecyclerView中使用包涵mattes或者mask的动画,否则会引起bitmap抖动。除了内存抖动,mattes和mask中必要的bitmap.eraseColor()和canvas.drawBitmap()也会降低动画性能。对于简单的动画,在实际使用时性能不太明显。

    如果在列表中使用动画,推荐使用缓存LottieAnimationView.setAnimation(String, CacheStrategy) 。

    2.属性动画和Lottie动画对比

    Lottie动画在未开启硬件加速的情况下,帧率、内存,CPU都比属性动画差,开启硬件加速后,性能差不多。

    3.未开启硬件加速,Lottie动画大小帧率对比

    主要耗时在draw方法,绘制区域越小,耗时越小

    六、总结

    1.劣势

    (1)性能不够好—某些动画特效,内存和性能不够好;相对于属性动画,在展示大动画时,帧率较低

    2.优势
    (1)开发效率高—代码实现简单,更换动画方便,易于调试和维护。
    (2)数据源多样性—可从assets,sdcard,网络加载动画资源,能做到不发版本,动态更新
    (3)跨平台—设计稿导出一份动画描述文件,android,ios,react native通用
    (4) Lottie使用简单,易于上手,非常值得尝试。

    七、文末福利

    1.Lottie动画库
    2.Lottie官方样例

    相关文章

      网友评论

        本文标题:Android Lottie动画使用

        本文链接:https://www.haomeiwen.com/subject/uymybftx.html