Lottie 动画库使用
Lottie
基本使用
- xmls常用属性
app:lottie_autoPlay="false" //自动播放 相当于 playAnimation()
app:lottie_fileName="lottiefiles.com - ATM.json"//设置动画文件 相当于setAnimation("xx.json")
app:lottie_loop="true" // loop(true)
app:lottie_progress="1.0f"//setProgerss(1.0f)
app:lottie_scale="0.5"//setScale(0.5f)
app:lottie_cacheStrategy="strong"
- 常用Api
animationView.loop(true);
animationView.setProgress(1.0f);
animationView.setScale(1f);
animationView.playAnimation();
animationView.isAnimating()
animationView.pauseAnimation();
animationView.cancelAnimation();
...
//设置动画的方式
setAnimation(String);
setAnimation(JSONObject)
setComposition(LottieComposition)
setAnimation(String animationName, CacheStrategy cacheStrategy)
//控制动画播放
playAnimation(int startFrame,int endFrame)
playAnimation(float startProgress, float endProgress)
如果在json文件中引用了图片资源,就需通过setImageAssetsFolder(“airbnb_loader/”)的方法设置其所在assets文件夹下的位置,否者会报错。
playAnimation(startFrame, endFrame)
playAnimation(startProgress, endProgress)
上面两个方法用来播放指定的帧区间内或者进度区间的动画,在Api内部playAnimation(startFrame, endFrame) 实际通过调用的是playAnimation(startProgress, endProgress),
public void playAnimation(final int startFrame, final int endFrame) {
...
playAnimation(startFrame / composition.getDurationFrames(),
endFrame / composition.getDurationFrames());
}
- 加载动画资源的方式
LottieComposition.Factory.fromAssetFileName(Context context, String fileName,OnCompositionLoadedListener loadedListener);
LottieComposition.Factory.fromInputStream(Context context, InputStream stream, OnCompositionLoadedListener loadedListener);
LottieComposition.Factory.fromJson(Resources res, JSONObject json, OnCompositionLoadedListener loadedListener);
除了简单粗暴的animationView.setAnimation(“lottiefiles.com - ATM.json”)方式去设置动画的json 文件还可以通过上面三种方式去加载,并在回调中设置动画。
public void setAnimation(final String animationName, final CacheStrategy cacheStrategy) {
...
compositionLoader = LottieComposition.Factory.fromAssetFileName(getContext(), animationName,
new OnCompositionLoadedListener() {
@Override
public void onCompositionLoaded(LottieComposition composition) {
if (cacheStrategy == CacheStrategy.Strong) {
STRONG_REF_CACHE.put(animationName, composition);
} else if (cacheStrategy == CacheStrategy.Weak) {
WEAK_REF_CACHE.put(animationName, new WeakReference<>(composition));
}
setComposition(composition);
}
});
}
可以看到在setAnimation(xx.josn)方法内部调用的是
LottieComposition.Factory.fromAssetFilName(Context context, String fileName,OnCompositionLoadedListener loadedListener),
在load 完成后直接通过 setComposition(composition)进行设置。
在LottieComposition.Factory.fromAssetFilName(Context context, String fileName,OnCompositionLoadedListener loadedListener) 内部又调用了fromAssetFileName,这..
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);
}
对于LottieComposition.Factory.fromJson(Resources res, JSONObject json, OnCompositionLoadedListener loadedListener) 方法 可以用来从网上加载出动画文件,在通过该方法进行load, 也可以通过setAnimation(JSONObject)方法直接进行设置,其内部调用了LottieComposition.Factory.fromJson方法
public void setAnimation(final JSONObject json) {
cancelLoaderTask();
compositionLoader = LottieComposition.Factory.fromJson(getResources(), json, loadedListener);
}
缓存策略(strong weak none三种)
- 如果要重复使用某个动画的话,可以为其设置缓存策略,你可以通过
java 代码
setAnimation(String animationName, CacheStrategy cacheStrategy)
xml 中设置
app:lottie_cacheStrategy="strong"
在setAnimal(String) 方法
public void setAnimation(String animationName) {
setAnimation(animationName, defaultCacheStrategy);
}
//不同缓存策略的方式
//两个map数组分别存放不同缓存策略的对象
private static final Map<String, LottieComposition> STRONG_REF_CACHE = new HashMap<>();
private static final Map<String, WeakReference<LottieComposition>> WEAK_REF_CACHE = new HashMap<>();
if (cacheStrategy == CacheStrategy.Strong) {
STRONG_REF_CACHE.put(animationName, composition);
} else if (cacheStrategy == CacheStrategy.Weak) {
WEAK_REF_CACHE.put(animationName, new WeakReference<>(composition));
}
其中默认的缓存为weak.
LottieAnimationView的监听
animationView.addAnimatorListener(Animator.AnimatorListener listener);
animationView.addAnimatorUpdateListener(ValueAnimator.AnimatorUpdateListener updateListener);
Lottie实现的基本过程
json文件 ——> LottieComposition ——> LottieDrawable ——> LottieAnimationView
- 首先了解json相关属性josn文件相关属性
"v": "4.10.1", bodymovin的版本//版本要求在4.5.0(包含4.5.0)以上
"fr": 25, 帧率
"ip": 0, 起始关键帧
"op": 350, 结束关键帧
"w": 1080, 图片宽度
"h": 1080, 图片高度
"nm": "day1", 图片名称
"assets": [], 图片集合
"layers": 图层集合
LottieCopposition 相当于一个model类,其中包含着所有的数据信息
在上面的几种设置动画的方式中,在其内部,通过FileCompositionLoader 把json文件数据信息加载到LottieComposition中
FileCompositionLoader loader =
new FileCompositionLoader(context.getResources(), loadedListener);
loader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, stream);
具体加载json的方法
static LottieComposition fromJsonSync(Resources res, JSONObject json) {
Rect bounds = null;
float scale = res.getDisplayMetrics().density;
int width = json.optInt("w", -1);
int height = json.optInt("h", -1);
if (width != -1 && height != -1) {
int scaledWidth = (int) (width * scale);
int scaledHeight = (int) (height * scale);
bounds = new Rect(0, 0, scaledWidth, scaledHeight);
}
long startFrame = json.optLong("ip", 0);
long endFrame = json.optLong("op", 0);
float frameRate = (float) json.optDouble("fr", 0);
String version = json.optString("v");
String[] versions = version.split("[.]");
int major = Integer.parseInt(versions[0]);
int minor = Integer.parseInt(versions[1]);
int patch = Integer.parseInt(versions[2]);
LottieComposition composition = new LottieComposition(
bounds, startFrame, endFrame, frameRate, scale, major, minor, patch);
JSONArray assetsJson = json.optJSONArray("assets");
parseImages(assetsJson, composition);
parsePrecomps(assetsJson, composition);
parseFonts(json.optJSONObject("fonts"), composition);
parseChars(json.optJSONArray("chars"), composition);
parseLayers(json, composition);
return composition;
}
LottieComposition类中还提供了一下几种静态方法来解析json文件
LottieComposition 中的静态方法来解析json文件
parseLayers(JSONObject json, LottieComposition composition)
parsePrecomps( @Nullable JSONArray assetsJson, LottieComposition composition)
parseImages(@Nullable JSONArray assetsJson, LottieComposition composition)
parseFonts(@Nullable JSONObject fonts, LottieCompositioncomposition)
parseChars(@Nullable JSONArray charsJson, LottieComposition composition)
addLayer(List<Layer> layers, LongSparseArray<Layer> layerMap, Layer layer)
- LottieDrawable 是Lottiecomposition数据的载体,以上的几种对LottieAnimationView设置数据的方式,都会调用LottieDrawable的 setComposition(LottieComposition composition) 方法
public void setComposition(@NonNull LottieComposition composition) {
if (L.DBG) {
Log.v(TAG, "Set Composition \n" + composition);
}
lottieDrawable.setCallback(this);
//下面方法判断是不是已经存在的信息
boolean isNewComposition = lottieDrawable.setComposition(composition);
enableOrDisableHardwareLayer();
if (!isNewComposition) {
// We can avoid re-setting the drawable, and invalidating the view, since the composition
// hasn't changed.
return;
}
//view的适配
int screenWidth = Utils.getScreenWidth(getContext());
int screenHeight = Utils.getScreenHeight(getContext());
int compWidth = composition.getBounds().width();
int compHeight = composition.getBounds().height();
if (compWidth > screenWidth ||
compHeight > screenHeight) {
float xScale = screenWidth / (float) compWidth;
float yScale = screenHeight / (float) compHeight;
float maxScaleForScreen = Math.min(xScale, yScale);
setScale(Math.min(maxScaleForScreen, lottieDrawable.getScale()));
// If you set a different composition on the view, the bounds will not update unless
// the drawable is different than the original.
setImageDrawable(null);
setImageDrawable(lottieDrawable);
this.composition = composition;
requestLayout();
}
Lottie中做了状态的保存,保存了动画的一些属性,状态,以及进度等等。在屏幕旋转以及其他场景,需要保存状态的时候,不用我们自己保存。
@Override protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.animationName = animationName;
ss.progress = lottieDrawable.getProgress();
ss.isAnimating = lottieDrawable.isAnimating();
ss.isLooping = lottieDrawable.isLooping();
ss.imageAssetsFolder = lottieDrawable.getImageAssetsFolder();
return ss;
}
@Override protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
this.animationName = ss.animationName;
if (!TextUtils.isEmpty(animationName)) {
setAnimation(animationName);
}
setProgress(ss.progress);
loop(ss.isLooping);
if (ss.isAnimating) {
playAnimation();
}
lottieDrawable.setImagesAssetsFolder(ss.imageAssetsFolder);
}
库的使用相对简单,能实现复杂的效果,可以很灵活的去设置动画的,无论从网络或者本地获取,同时支持绝大多数AE效果,能够满足正常的需求,亲测好用 ,值得推荐。
详情见官方文档:airbnb.io/lottie
下一篇: 10_Android的消息机制