Android -Lottie加載動(dòng)畫喂飯指南

簡單的說,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'
}

image.gif

這里需要注意的是,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();

image.gif

或者只使用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" />
image.gif

使用服務(wù)器json文件

LottieComposition.Factory
         .fromJson(getResources(), json, new OnCompositionLoadedListener() {
          @Override
          public void onCompositionLoaded(LottieComposition composition) {
             lottieAnimationView.setComposition(composition);
             lottieAnimationView.playAnimation();
  }
});
image.gif

使用服務(wù)器上zip文件

1、直接網(wǎng)絡(luò)加載:

lottieAnimationView.setAnimationFromUrl(ZIPURL);
lottieAnimationView.playAnimation();
image.gif

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();
                }
            }
        }
    }

image.gif
/** 
 * 刪除整個(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();
}
image.gif

使用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();
        }

    }
image.gif

另外,我們?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();    
       }
});
image.gif

動(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é)束}          }
    }
);
image.gif

也可以使用下邊監(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ù)    
    }
});
image.gif

自動(dòng)播放

lottie_autoPlay="true"
image.gif

循環(huán)播放

app:lottie_loop="true"
image.gif

或者

lottieAnimationView.loop(true);
image.gif

播放

lottieAnimationView.playAnimation();
image.gif

暫停播放

lottieAnimationView.pauseAnimation();
image.gif

取消播放

lottieAnimationView.cancelAnimation();
image.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容