簡單的說,Lottie就是airbnb開源的一個(gè)使用json文件快速加載動(dòng)畫且支持多平臺(tái)的庫。
更多介紹請(qǐng)查看官網(wǎng)。官網(wǎng)地址:https://airbnb.design/lottie/
怎么使用Lottie
在項(xiàng)目的build.gradle文件中直接添加依賴:
dependencies {
implementation 'com.airbnb.android:lottie:$lottieVersion'
}

這里需要注意的是,lottie最低支持API 16,Lottie版本2.8.0及其以上升級(jí)了androidx,本篇文章主要介紹2.7.0的使用方法。
關(guān)于最新版本請(qǐng)查看lottie的GitHub地址:https://github.com/airbnb/lottie-android,現(xiàn)在最新版本號(hào)已經(jīng)到了3.4.0,版本更新有些快。
加載動(dòng)畫方式
使用資產(chǎn)文件(src/main/assets)
將json文件和image文件夾放到資產(chǎn)文件下方,代碼加載:
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" />

使用服務(wù)器json文件
LottieComposition.Factory
.fromJson(getResources(), json, new OnCompositionLoadedListener() {
@Override
public void onCompositionLoaded(LottieComposition composition) {
lottieAnimationView.setComposition(composition);
lottieAnimationView.playAnimation();
}
});

使用服務(wù)器上zip文件
1、直接網(wǎng)絡(luò)加載:
lottieAnimationView.setAnimationFromUrl(ZIPURL);
lottieAnimationView.playAnimation();

2、下載zip文件本地解壓加載
關(guān)于文件下載這里就不多介紹了,網(wǎng)絡(luò)上有很多介紹。下載zip文件之后我們要進(jìn)行解壓縮:
/**
* 解壓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();
}
}
}
}

/**
* 刪除整個(gè)文件夾 或者 文件
*/
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加載本地動(dòng)畫資源:
/**
* 加載本地動(dòng)畫資源
* @param lottieAnimationView 展示動(dòng)畫view
* @param imagesPath 本地動(dòng)畫資源圖片地址
* @param dataPath 本地動(dòng)畫資源json數(shù)據(jù)地址
*/
public static void loadLottie(LottieAnimationView lottieAnimationView,String imagesPath,String dataPath){
// 動(dòng)效圖片資源
final File imagesFiles = new File(imagesPath);
// data.json路徑
final File jsonFile = new File(dataPath);
if (!jsonFile.exists() || !imagesFiles.exists()) {
Log.e("lottieUtils", "動(dòng)畫資源不存在");
return;
}
try {
FileInputStream fis = new FileInputStream(jsonFile);
final String absolutePath = imagesFiles.getAbsolutePath();
// 開啟硬件加速
lottieAnimationView.useHardwareAcceleration(true);
// 設(shè)置動(dòng)畫文件夾代理類
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;
}
});
// 設(shè)置動(dòng)畫
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();
}
}

另外,我們?cè)谙螺d動(dòng)畫資源到本地之后,手機(jī)相冊(cè)會(huì)自動(dòng)掃描到,這樣相冊(cè)里會(huì)有很多動(dòng)畫分解的圖片,一是對(duì)于相冊(cè)展示不太好,二是用戶有可能會(huì)刪除某張分解動(dòng)畫的圖片。所以,這里簡單介紹下一下2種避免圖片自動(dòng)掃描到相冊(cè)的方法:
1、創(chuàng)建隱藏文件夾存放動(dòng)畫資源,只需要在文件名前加. (例如:.lottie)。
2、在存儲(chǔ)動(dòng)畫資源的文件的文件夾下添加.nomedia 文件,告訴系統(tǒng)改文件夾下沒有多媒體 文件。
常用API
成功和失敗監(jiān)聽
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();
}
});

動(dòng)畫進(jìn)度監(jiān)聽
lottieAnimationView.addAnimatorUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
if (valueAnimator.getAnimatedFraction() == 0 ){
//動(dòng)畫開始
}else if (valueAnimator.getAnimatedFraction() == 1f){
//動(dòng)畫結(jié)束} }
}
);

也可以使用下邊監(jiān)聽:
lottieAnimationView.addAnimatorListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
//動(dòng)畫開始
}
@Override
public void onAnimationEnd(Animator animator) {
//動(dòng)畫結(jié)束
}
@Override
public void onAnimationCancel(Animator animator) {
//動(dòng)畫取消
}
@Override
public void onAnimationRepeat(Animator animator) {
//動(dòng)畫重復(fù)
}
});

自動(dòng)播放
lottie_autoPlay="true"

循環(huán)播放
app:lottie_loop="true"

或者
lottieAnimationView.loop(true);

播放
lottieAnimationView.playAnimation();

暫停播放
lottieAnimationView.pauseAnimation();

取消播放
lottieAnimationView.cancelAnimation();
