简单的说,Lottie就是airbnb开源的一个使用json文件快速加载动画且支持多平台的库。
更多介绍请查看官网。官网地址:https://airbnb.design/lottie/
怎么使用Lottie
在项目的build.gradle文件中直接添加依赖:
dependencies {
implementation 'com.airbnb.android:lottie:$lottieVersion'
}
这里需要注意的是,lottie最低支持API 16,Lottie版本2.8.0及其以上升级了androidx,本篇文章主要介绍2.7.0的使用方法。
关于最新版本请查看lottie的GitHub地址:https://github.com/airbnb/lottie-android,现在最新版本号已经到了3.4.0,版本更新有些快。
加载动画方式
使用资产文件(src/main/assets)
将json文件和image文件夹放到资产文件下方,代码加载:
lottieAnimationView.setImageAssetsFolder(imagesPath);
lottieAnimationView.setAnimation(jsonPath);
lottieAnimationView.playAnimation();
或者只使用json文件可在xml文件中直接加载:
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottieAnimationView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:lottie_fileName="test.json"
app:lottie_loop="true"
app:lottie_autoPlay="true" />
使用服务器json文件
LottieComposition.Factory
.fromJson(getResources(), json, new OnCompositionLoadedListener() {
@Override
public void onCompositionLoaded(LottieComposition composition) {
lottieAnimationView.setComposition(composition);
lottieAnimationView.playAnimation();
}
});
使用服务器上zip文件
1、直接网络加载:
lottieAnimationView.setAnimationFromUrl(ZIPURL);
lottieAnimationView.playAnimation();
2、下载zip文件本地解压加载
关于文件下载这里就不多介绍了,网络上有很多介绍。下载zip文件之后我们要进行解压缩:
/**
* 解压assets的zip压缩文件到指定目录(包含子目录)
* @param zipFileName 压缩文件名
* @param outputDirectory 输出目录
* @throws IOException
*/
public static void unZip(String zipFileName, String outputDirectory) {
ZipFile zipFile = null;
try {
zipFile = new ZipFile(zipFileName);
Enumeration e = zipFile.entries();
ZipEntry zipEntry;
File dest = new File(outputDirectory);
dest.mkdirs();
while (e.hasMoreElements()) {
zipEntry = (ZipEntry) e.nextElement();
String entryName = zipEntry.getName();
InputStream in = null;
FileOutputStream out = null;
try {
if (zipEntry.isDirectory()) {
String name = zipEntry.getName();
name = name.substring(0, name.length() - 1);
File f = new File(outputDirectory + File.separator
+ name);
f.mkdirs();
} else {
int index = entryName.lastIndexOf("\\");
if (index != -1) {
File df = new File(outputDirectory + File.separator
+ entryName.substring(0, index));
df.mkdirs();
}
index = entryName.lastIndexOf("/");
if (index != -1) {
File df = new File(outputDirectory + File.separator
+ entryName.substring(0, index));
df.mkdirs();
}
File f = new File(outputDirectory + File.separator
+ zipEntry.getName());
in = zipFile.getInputStream(zipEntry);
out = new FileOutputStream(f);
int c;
byte[] by = new byte[1024];
while ((c = in.read(by)) != -1) {
out.write(by, 0, c);
}
out.flush();
}
} catch (IOException ex) {
ex.printStackTrace();
Log.e("unZip", "解压失败:" + ex.toString());
UnAnimationZipFinshEvent.post("Zip.class", false,null);
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
Log.e("unZip", "解压成功");
UnAnimationZipFinshEvent.post("Zip.class", true,outputDirectory);
deleteDir(new File(zipFileName));
} catch (IOException ex) {
ex.printStackTrace();
Log.e("unZip", "解压失败:" + ex.toString());
UnAnimationZipFinshEvent.post("Zip.class", false,null);
} finally {
if (zipFile != null) {
try {
zipFile.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
/**
* 删除整个文件夹 或者 文件
*/
private static void deleteDir(File file) {
if (!file.exists()) {
return;
}
if (file.isDirectory()) {
File[] childFiles = file.listFiles();
if (childFiles == null || childFiles.length == 0) {
file.delete();
}
for (File childFile : childFiles) {
deleteDir(childFile);
}
}
file.delete();
}
使用Lottie加载本地动画资源:
/**
* 加载本地动画资源
* @param lottieAnimationView 展示动画view
* @param imagesPath 本地动画资源图片地址
* @param dataPath 本地动画资源json数据地址
*/
public static void loadLottie(LottieAnimationView lottieAnimationView,String imagesPath,String dataPath){
// 动效图片资源
final File imagesFiles = new File(imagesPath);
// data.json路径
final File jsonFile = new File(dataPath);
if (!jsonFile.exists() || !imagesFiles.exists()) {
Log.e("lottieUtils", "动画资源不存在");
return;
}
try {
FileInputStream fis = new FileInputStream(jsonFile);
final String absolutePath = imagesFiles.getAbsolutePath();
// 开启硬件加速
lottieAnimationView.useHardwareAcceleration(true);
// 设置动画文件夹代理类
lottieAnimationView.setImageAssetDelegate(new ImageAssetDelegate() {
@Override
public Bitmap fetchBitmap(LottieImageAsset asset) {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = true;
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeFile(absolutePath + File.separator + asset.getFileName(), opts);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
});
// 设置动画
LottieComposition.Factory.fromInputStream(fis, new OnCompositionLoadedListener() {
@Override
public void onCompositionLoaded(@Nullable LottieComposition composition) {
lottieAnimationView.setComposition(composition);
lottieAnimationView.playAnimation();
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
另外,我们在下载动画资源到本地之后,手机相册会自动扫描到,这样相册里会有很多动画分解的图片,一是对于相册展示不太好,二是用户有可能会删除某张分解动画的图片。所以,这里简单介绍下一下2种避免图片自动扫描到相册的方法:
1、创建隐藏文件夹存放动画资源,只需要在文件名前加. (例如:.lottie)。
2、在存储动画资源的文件的文件夹下添加.nomedia 文件,告诉系统改文件夹下没有多媒体 文件。
常用API
成功和失败监听
LottieCompositionFactory.fromUrl(this,ZIPURL)
.addFailureListener(new LottieListener<Throwable>() {
@Override
public void onResult(Throwable result) {
// TODO: 添加加载失败逻辑
}
}).addListener(new LottieListener<LottieComposition>() {
@Override
public void onResult(LottieComposition result) {
lottieAnimationView.setComposition(result);
lottieAnimationView.playAnimation();
}
});
动画进度监听
lottieAnimationView.addAnimatorUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
if (valueAnimator.getAnimatedFraction() == 0 ){
//动画开始
}else if (valueAnimator.getAnimatedFraction() == 1f){
//动画结束} }
}
);
也可以使用下边监听:
lottieAnimationView.addAnimatorListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
//动画开始
}
@Override
public void onAnimationEnd(Animator animator) {
//动画结束
}
@Override
public void onAnimationCancel(Animator animator) {
//动画取消
}
@Override
public void onAnimationRepeat(Animator animator) {
//动画重复
}
});
自动播放
lottie_autoPlay="true"
循环播放
app:lottie_loop="true"
或者
lottieAnimationView.loop(true);
播放
lottieAnimationView.playAnimation();
暂停播放
lottieAnimationView.pauseAnimation();
取消播放
lottieAnimationView.cancelAnimation();