作者 | 负了时光不负卿
地址 | http://www.jianshu.com/p/89c64253fd77
声明 | 本文是 负了时光不负卿 原创,已获授权发布,未经原作者允许请勿转载
入坑背景
由于从事直播软件开发的缘故,本猿在版本迭代过程中一期不落的接触到各式各样动画效果。最早的时候,苦逼的用 Android 原生动画做直播间全屏礼物,反复的看着美工给的 Flash 效果图,不断的拼凑素材图片,调整控制动画播放的属性值,各个动画代码都很类似,但却无法套用,一连两三天下来,基本上脑海中除了动画就一片空白
踩坑准备
熟悉一个新的框架最快的方式就是查看官方文档,因为官方文档中一般都会给出一个 Demo,果不其然,Lottie 也是!文档的阅读量不是很大,通篇下来介绍了:
播放本地 Assets 目录下的 Json 动画文件
通过 Json 数据播放动画
如何对动画进行监听以及动画进度调节
Lottie 动画数据的预加载和缓存
为 Assets 目录下的 Json 动画文件配置动画所需要的素材
开始入坑
然而,他介绍了这么多,并没有一款适合我的。因为服务器下发不是简单的 Json 数据,是一个动画压缩包,里面包括了动画文件和播放动画需要的素材文件,而且解压后的文件也不在 Asset 目录下。于是,只好跟踪 animationView.setAnimation("hello-world.json")源码,看看最终到底做了什么事!
public void setAnimation(String animationName) {
setAnimation(animationName, defaultCacheStrategy);
}
一个参数调用两个参数同名方法,只好接着往下看!
public void setAnimation(final String animationName, final CacheStrategy cacheStrategy) {
this.animationName = animationName;
if (weakRefCache.containsKey(animationName)) {
WeakReference<LottieComposition> compRef = weakRefCache.get(animationName);
if (compRef.get() != null) {
setComposition(compRef.get());
return;
}
} else if (strongRefCache.containsKey(animationName)) {
setComposition(strongRefCache.get(animationName));
return;
}
this.animationName = animationName;
lottieDrawable.cancelAnimation();
cancelLoaderTask();
compositionLoader = LottieComposition.Factory.fromAssetFileName(getContext(), animationName,
new OnCompositionLoadedListener() {
@Override
public void onCompositionLoaded(LottieComposition composition) {
if (cacheStrategy == CacheStrategy.Strong) {
strongRefCache.put(animationName, composition);
} else if (cacheStrategy == CacheStrategy.Weak) {
weakRefCache.put(animationName, new WeakReference<>(composition));
}
setComposition(composition);
}
});
}
从这里可以看到官方文档中说的缓存,包括强引用缓存,弱引用缓存,和无缓存模式,而且知道 Json 动画文件最终会转化为 Composition 对象,而 Compostion 对象是通过 LottieComposition
public static Cancellable fromAssetFileName(Context context, String fileName,
OnCompositionLoadedListener loadedListener) {
InputStream stream;
try {
stream = context.getAssets().open(fileName);
} catch (IOException e) {
throw new IllegalStateException("Unable to find file " + fileName, e);
}
return fromInputStream(context, stream, loadedListener);
}
看到这里我们这就明白,当初传入的文件名,最终还是通过getAssets().open(fileName) 的方法,以流的方式进行处理了,于是我们可以这样加载放在其他目录下的 Json 动画文件。