酷炫的动画库——Lottie 源码解析 第二章
在上一节,我们分析了LottieView的playAnimation()的整体流程,我们在最后也提到了,Lottie的动画就是通过一层一层的Layer实现的,其中有CompositionLayer、BaseLayer比较重要,起到了通知更新、分发更新的作用。但是上一节没有具体分析Lottie从 Json文件到动画文件(Layer)到底做了什么,是怎么解析的。这一节的内容,我们就来看下这一部分的内容。
首先,通过LottieView的使用可以看的出来,解析json并且给LottieView设置,是通过如下代码:
1 | LottieCompositionFactory.fromAsset(context, "assertName").addListener{ |
通过这段代码实际上可以看的出来,Lottie是将一个assert文件解析为Composition这个对象,然后给LottieView,那么这个 LottieCompositionFactory.fromAssert()
就是解析文件的过程,所以,首先从这个方法看起:
1 | public static LottieTask<LottieComposition> fromAsset(Context context, final String fileName) { |
可以看到这里调用了一个 cache()
方法, 从方法名就可以看出来,这是一个和缓存有关的方法,并且传入了一个Callable,那接下来看看cache的实现:
1 | private static LottieTask<LottieComposition> cache( |
cache()
方法的调用过程注释都写的很清楚,可以看到Lottie对动画做了缓存,但是从代码也可以看出来,这个缓存是以动画文件名称做key的,所以,如果说你更新了动画文件,需要重启App才能够生效了。
其次,这里的LottieTask有点类似AsyncTask,其内部包含了一个线程池用来处理异步任务,但是具体实现实在上面代码中的callbale,关键就是 fromAssetSync(appContext, fileName);
这句代码, 看下实现:
1 |
|
这个方法是一个异步方法,解析动画文件(zip或者json文件), 然后 fromJsonInputStreamSync
经过一系列调用最终会调用到 fromJsonReaderSyncInternal
:
1 | private static LottieResult<LottieComposition> fromJsonReaderSyncInternal( |
可以看到,具体的解析是由LottieCompositionMoshiParser解析的:
1 | private static final JsonReader.Options NAMES = JsonReader.Options.of( |
上面是 LottieCompositionMoshiParser
类中,对于一些json对象名称的定义,对应的是Lottie动画的Json文件,这些类型就是在解析的时候,区分将当前对象作为什么解析,来看一下parse方法,就能够明白这些类型的作用:
1 | public static LottieComposition parse(JsonReader reader) throws IOException { |
通过上面的方法,可以将Lottie的动画文件解析为相应的 Layers / images / fonts / markers 等等,然后会全部组装成composition,回调给LottieView。下面是一个示例的动画json文件,可以对应这个文件再看一下解析过程,会更加清晰:
1 | { |
所以,经过上述过程,最终会将动画文件包装成composition回调给LottieView,调用 LottieAnimationView.setComposition(composition)
:
1 | public void setComposition(@NonNull LottieComposition composition) { |
在这个方法中,就是将composition设置给了LottieDrawable,之后再调用playAnimation的话,就会走我们在第一节中说过的流程了,需要注意的是,这里还调用了requestLayout()
,也就是说,当调用了 setComposition
之后,动画就会显示出来,但是不会播放。
最后给一张加载动画文件整体流程图:
到这里,整个Lottie的工作流程以及解析过程就整理完成了,如果在项目中,对动画效果要求较好,或者有很多复杂动画的话,使用Lottie库还是很不错的。最后再总结一下Lottie中的几个关键点以及一些注意的事项:
关键类
- LottieComposition
包含Layer、LottieImageAsset、Font、FontCharacter
使用该类来转换AE的数据对象,将json映射到该类。方便之后转换为Drawable。
- LottieCompositionFactory
创建LottieComposition的工厂类,可以从网络加载,从文件加载,从assert 加载等等。
- LottieCompositionMoshiParser
LottieComposition解释器, 根据约定的解析规则,将json 数据格式解析为LottieComposition。
- LottieDrawable
在该类中,将解析后的LottieComposition转换为LottieDrawable,并且是主要的动画承载者。
- LayoutParser
LottieDrawable会将动画的json文件解析为一个一个的layer,包括CompositionLayer、SolidLayer、ImageLayer、ShapeLayer、TextLayer。最后会通过渲染这些图层、达到动画的效果。
可能存在问题
- 在有遮罩或者毛玻璃/磨砂的效果的时候,渲染的性能与时间消耗是没有这些特殊效果的一倍以上。可以参考BaseLayer源码中:
1 | //没有mask与matte的情况下,直接返回 |
- 如果动画的播放会比较卡,原因是什么?(原因可能是没有开启硬件加速)