Lottie是什么?

今天接手一个新项目的时候发现以前的同事引入了Lottie库,因为之前没有接触过后来百度了一下发现原来这个库主要是用来实现一些比较复杂的动画的。下面是官方的介绍,Lottie是Airbnb开源的一个支持Android、ios以及ReactNative,利用json文件的方式快速的实现动画效果的库,接下来就介绍一下它的如何使用的。

最开始我们就去github上看看它的源代码以及Demo:

https://github.com/airbnb/lottie-android

以前我们在实现动画的时候一般都有以下几种方式:

  • 使用帧动画。这种方式就是多张图片连续的切换,所以可想而知一个最大的弊端就是会导致最后的apk会非常的大。
  • 使用Gif。gif的话可以实现很多复杂的动画,但是我们知道Android本身是不支持gif的,而且还需要为各种屏幕的尺寸和分辨率做适配的,还有一个很重要的问题就是gif也会导致apk非常大的。
  • 使用代码实现,比如说补间动画和属性动画来实现很多复杂的动画,但是对于有些不擅长于写动画的童鞋来说是一个头痛的问题。
    为了解决上述等等各种问题,懒惰的人们就开发一款可以跨平台的动画框架,动画的路径数据就用一种通用的格式来记录,然后中间的话就分别用对应的平台来实现动画的走动。所以这个时候Lottie就出现了。

设计师的工作(其实这边我们可以不关心)

  • 首先我们让设计使用Adobe的Afeter Effects(简称AE)工具制作这个动画。
  • 然后需要在AE中安装一个叫做Bodymovin的插件,解压缩之后只需要\build\extension\bodymovin.zxp这个档案就可以
  • android lottie显示小的问题 android lottie原理_android

  • 手动安装plugin,以window系统而言,要先下载ExMan Command Line tool 并解压缩,再把下载的bodymovin压缩后的bodymovin-master/build/extension 目录下的bodymovin.zxp这个档案复制进去同一个资料夹。
  • android lottie显示小的问题 android lottie原理_android_02

  • 去找cmd,并以系统管理员身份执行。
  • android lottie显示小的问题 android lottie原理_json_03

  • 打开 ExManCmd_win所在的路径,进入ExManCmd_win的资料夹中
  • 接着打 ExManCmd.exe /install bodymovin.zxp 就完成了
  • 再来进入AE 后,可以在windows/extentions/bodymovin 找到插件,开启后按下Render 就完成了。 重点来了,这时会在你选的Destination Folder目录中生成一个json格式的文件,这个 json 文件描述了该动画的一些关键点的坐标以及运动轨迹,然后再转发给开发人员。

工程师的工作

  • 首先我们需要在build.gradle 文件引入动画框架
dependencies {  
     compile 'com.airbnb.android:lottie:2.0.0-beta4'
}

根据平时的经验我们都知道UI给我们的动画文件或者是资源文件都会放到drawable目录下去的,但是这次 UI 给我们的动画文件我们只能放到Assets目录下的,并不能放到其他的目录下,因为只有这样子的框架才能更好的找到其路径的。下面我们分别的来介绍三种方式加载动画文件。

1. Assets目录默认加载
首先我们将动画文件放到默Assets目录下,然后在layout布局文件中直接引用就可以了,其中fileName就是对应Assets目录下的文件的名字;loop true表示循环播放,false表示只播放一次; auto_play表示一开始就自动播放,设置false的话,就需要自己手动的调用 playAnimation() 来手动进行播放控制

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

2. 从网络上直接获取json数据进行加载

public void loadRemoteLottie() {
    Request request;
    try {
        request = new Request.Builder().url(url).build();
    } catch (IllegalArgumentException e) {
        return;
    }

    if (client == null) {
        client = new OkHttpClient();
    }
    client.newCall(request).enqueue(new Callback() {
        public void onFailure(Call call, IOException e) {
        }

        public void onResponse(Call call, Response response) throws IOException {
            if (response.isSuccessful()) {
                try {
                    JSONObject json = new JSONObject(response.body().string());
                    LottieComposition.Factory.fromJson(mResource, json, 
                                        new OnCompositionLoadedListener() {
                        @Override
                        public void onCompositionLoaded(LottieComposition lottieComposition) {
                            animation_view_network.setProgress(0);
                            animation_view_network.loop(true);
                            animation_view_network.setComposition(composition);
                            animation_view_network.playAnimation();
                        }
                    });
                } catch (JSONException e) {

                }
            }
        }
    });
}

我们可以通过获取远程json数据的这种格式来动态的配置应用里面的动画,这里面有几个要注意的问题:

  1. 这里我们在不能再像以前样子在layout中配置那些属性,这个时候我们只需要在xml中写一个简单的布局文件就可,如果你再设置那些属性的话,比如说你设置了自动播放和循环播放,但是你都还没有加载到资源,所以这个时候会有问题的。
  2. 这种通过获取json字符串来实现动画的方式,里面不能包含有图片,比如UE在做动画的时候有时候可能会带有图片的(特殊要求,比如说有些json不能实现的复杂的图片),这个时候如果还是通过这种方式再去加载的话,它会找不到路径的。

3. 从本地加载带有图片的文件
    有的时候UI做的AE动画文件中可能会带有图片的,这个时候如果你再使用原来那种通过获取json字符串的方式去获取本地文件的字符串的时候,这个时候会报一个内部的 You must set an images folder before loading an image. Set it with LottieComposition#setImagesFolder or LottieDrawable#setImagesFolder 因为它有图片,需要我们根据设定的路径去寻找图片并且渲染出来,这个后期我们会慢慢的分析。

private void loadLocal() {
        String sdcardPath = Environment.getExternalStorageDirectory();
        String path = sdcardPath + "/test_animation/newtest/data.json";
        final String imageFolder = sdcardPath + "/test_animation/newtest/images/";
        //1. 开始的时候我们需要设置它的图片存储的地方
        animation_view_network.setImageAssetsFolder(imageFolder);
        File file = new File(path);
        if(file.exists()) {
            try {
                FileInputStream fis = new FileInputStream(file);
                LottieComposition.Factory.fromInputStream(this, fis, 
                                                    new OnCompositionLoadedListener() {
                    @Override
                    public void onCompositionLoaded(LottieComposition lottieComposition) {
                        setComposition(lottieComposition);
                    }
                });
                //2. 然后调用该方法分别的去获取对应图片的地址,然后转化为Bitmap
                animation_view_network.setImageAssetDelegate(new ImageAssetDelegate() {
                    @Override
                    public Bitmap fetchBitmap(LottieImageAsset lottieImageAsset) {
                        String path = imageFolder + lottieImageAsset.getFileName();
                        BitmapFactory.Options opts = new BitmapFactory.Options();
                        opts.inScaled = true;
                        opts.inDensity = 160;
                        Bitmap bitmap = BitmapFactory.decodeFile(path, opts);
                        return bitmap;
                    }
                });
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

     本次我们只是对Lottie Android做一个最基本如何使用它,但是我们学习一个框架的目的不仅仅只是为了学会使用它,更关键的是如何去学习它的思想以及一些好的代码规划。比如说对于本框架来说,我们的目的就是先弄清楚它里面的实现逻辑以及一些好的代码规范的,这样子我们以后也可以写出一个属于自己的框架。下面将会结合官方的例子以及代码将代码和demo放在一起,然后放在csdn上,感兴趣的同学可以在上面下载。

感激以下文章

Lottie- 让Android动画实现更简单