Lottie 源码解析
1 LottieAnimationView
LottieAnimationView继承AppCompatImageView 用来加载,反序列化,展示来自于ae生成的json
构造调用了init();
private void init(@Nullable AttributeSet attrs) {
//加载自定义属性
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.LottieAnimationView);
//composition的缓存策略,默认为none, composition的作用是从json中产生动画操作
int cacheStrategyOrdinal = ta.getInt(R.styleable.LottieAnimationView_lottie_cacheStrategy,DEFAULT_CACHE_STRATEGY.ordinal());
this.defaultCacheStrategy = CacheStrategy.values()[cacheStrategyOrdinal];
//判断view是否处于编辑状态
if (!isInEditMode()) {
//json是否是res/raw文件
boolean hasRawRes = ta.hasValue(R.styleable.LottieAnimationView_lottie_rawRes);
//json是否是assets文件
boolean hasFileName = ta.hasValue(R.styleable.LottieAnimationView_lottie_fileName);
//二者不能同时进行
if (hasRawRes && hasFileName) {
throw new IllegalArgumentException(“lottie_rawRes and lottie_fileName cannot be used at ” +
“the same time. Please use use only one at once.”);
} else if (hasRawRes) {//json来自res
int rawResId = ta.getResourceId(R.styleable.LottieAnimationView_lottie_rawRes, 0);
if (rawResId != 0) {
setAnimation(rawResId);//设置json文件res id
}
} else if (hasFileName) {//json来自assets
String fileName = ta.getString(R.styleable.LottieAnimationView_lottie_fileName);
if (fileName != null) {
setAnimation(fileName);//设置json文件的名字
}
}
}
//判断是否自动播放
if (ta.getBoolean(R.styleable.LottieAnimationView_lottie_autoPlay, false)) {
wasAnimatingWhenDetached = true;//根据名字猜测,动画是否绑定
autoPlay = true;
}
//判断是否无限轮播,如果是则轮播次数为int的最大值
//lottieDrawable.setRepeatCount-〉animator.setRepeatCount(count);
//lottieDrawable继承自Drawable,个人理解的翻译:用来显示执行动画
//animator是LottieValueAnimator的对象,LottieValueAnimator继承BaseLottieAnimator,BaseLottieAnimator的父类是ValueAnimator
if (ta.getBoolean(R.styleable.LottieAnimationView_lottie_loop, false)) {
lottieDrawable.setRepeatCount(LottieDrawable.INFINITE);
}
//重复模式,执行完一次以后是否反向执行
//lottieDrawable.setRepeatMode -〉animator.setRepeatMode
if (ta.hasValue(R.styleable.LottieAnimationView_lottie_repeatMode)) {
setRepeatMode(ta.getInt(R.styleable.LottieAnimationView_lottie_repeatMode,
LottieDrawable.RESTART));
}
//重复动画的次数
if (ta.hasValue(R.styleable.LottieAnimationView_lottie_repeatCount)) {
setRepeatCount(ta.getInt(R.styleable.LottieAnimationView_lottie_repeatCount,
LottieDrawable.INFINITE));
}
//当实使用的json中包括图片时,需要设置这个图片在assets文件夹的相对路径
//lottieDrawable.setImagesAssetsFolder(imageAssetsFolder)-〉this.imageAssetsFolder = imageAssetsFolder(在lottiedrawable类中)
//-〉在ImageAssetManager类中会用到,此类的作用是将json中用到的图片转换为bitmap,并回收bitmap
setImageAssetsFolder(ta.getString(R.styleable.LottieAnimationView_lottie_imageAssetsFolder));
//设置进度,有一个回调就是给动画添加addAnimatorUpdateListener(传listenser)可在回调中拿到ValueAnimator对象,可以获取到LottieAnimationView执行的进度等
setProgress(ta.getFloat(R.styleable.LottieAnimationView_lottie_progress, 0));
//具体作用还没搞懂,翻译是用来在api19或者更高级别合并路径
enableMergePathsForKitKatAndAbove(ta.getBoolean(
R.styleable.LottieAnimationView_lottie_enableMergePathsForKitKatAndAbove, false));
//是否设置着色器
if (ta.hasValue(R.styleable.LottieAnimationView_lottie_colorFilter)) {
//具体神什么作用还得再看一下
SimpleColorFilter filter = new SimpleColorFilter(
ta.getColor(R.styleable.LottieAnimationView_lottie_colorFilter, Color.TRANSPARENT));
KeyPath keyPath = new KeyPath(“**”);
LottieValueCallback callback = new LottieValueCallback(filter);
addValueCallback(keyPath, LottieProperty.COLOR_FILTER, callback);
}
//是否缩放
if (ta.hasValue(R.styleable.LottieAnimationView_lottie_scale)) {
lottieDrawable.setScale(ta.getFloat(R.styleable.LottieAnimationView_lottie_scale, 1f));
}
ta.recycle();
//是否开启硬件加速
enableOrDisableHardwareLayer();
}
下面看一下init方法中setAnimation做了什么
setAnmation(animationName)-〉setAnimation(animationName, defaultCacheStrategy);
/**
从资产目录中的文件设置动画。这将异步加载和反序列化文件。
您也可以指定缓存策略。 一旦加载和反序列化,指定{@link CacheStrategy#Strong}将强制引用组合。 {@link CacheStrategy#Weak}将会对这个组合构成一个弱引用。
* Sets the animation from a file in the assets directory.
* This will load and deserialize the file asynchronously.
*
* You may also specify a cache strategy. Specifying {@link CacheStrategy#Strong} will hold a
* strong reference to the composition once it is loaded
* and deserialized. {@link CacheStrategy#Weak} will hold a weak reference to said composition.
*/
public void setAnimation(final String animationName, final CacheStrategy cacheStrategy) {
this.animationName = animationName;
animationResId = 0;
//如果已经转换过的就直接设置
if (ASSET_WEAK_REF_CACHE.containsKey(animationName)) {
WeakReference compRef = ASSET_WEAK_REF_CACHE.get(animationName);
LottieComposition ref = compRef.get();
if (ref != null) {
setComposition(ref);//给动画设置composition
return;
}
} else if (ASSET_STRONG_REF_CACHE.containsKey(animationName)) {
setComposition(ASSET_STRONG_REF_CACHE.get(animationName));//给动画设置composition
return;
}
clearComposition();
cancelLoaderTask();
//异步将json转换为composition
compositionLoader = LottieComposition.Factory.fromAssetFileName(getContext(), animationName,
new OnCompositionLoadedListener() {
@Override public void onCompositionLoaded(LottieComposition composition) {
if (cacheStrategy == CacheStrategy.Strong) {
ASSET_STRONG_REF_CACHE.put(animationName, composition);
} else if (cacheStrategy == CacheStrategy.Weak) {
ASSET_WEAK_REF_CACHE.put(animationName, new WeakReference<>(composition));
}
//给动画设置composition
setComposition(composition);
}
});
}
下面看一下compositionLoader = LottieComposition.Factory.fromAssetFileName做了什么工作
/**
从assets文件夹下的文件中load composition
* Loads a composition from a file stored in /assets.
*/
public static Cancellable fromAssetFileName(
Context context, String fileName, OnCompositionLoadedListener listener) {
InputStream stream;
try {
stream = context.getAssets().open(fileName);//将json文件转换为inputstream
} catch (IOException e) {
throw new IllegalArgumentException(“Unable to find file ” + fileName, e);
}
return fromInputStream(stream, listener);
}
接着看fromInputStream(stream, listener)的实现
/**
从任意输入流中加载合成composition,注意是任意流
* Loads a composition from an arbitrary input stream.
*
* ex: fromInputStream(context, new FileInputStream(filePath), (composition) -> {});
*/
public static Cancellable fromInputStream(
InputStream stream, OnCompositionLoadedListener listener) {
//将inputstream转换为Jsonreader
return fromJsonReader(new JsonReader(new InputStreamReader(stream)), listener);
}
接着看fromJsonReader(new JsonReader(new InputStreamReader(stream)), listener);
/**
从jsonreader中加载compisition
* Loads a composition from a json reader.
*
* ex: fromInputStream(context, new FileInputStream(filePath), (composition) -> {});
*/
public static Cancellable fromJsonReader(
JsonReader reader, OnCompositionLoadedListener listener) {
//AsyncCompositionLoader是asynctask,接下来看一下他的实现
AsyncCompositionLoader loader = new AsyncCompositionLoader(listener);
loader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, reader);
return loader;
}
AsyncCompositionLoader的实现
public final class AsyncCompositionLoader
extends AsyncTask