Lottie動畫學習一 —— 入門部落格介紹
Lottie是什麼?
今天接手一個新專案的時候發現以前的同事引入了Lottie庫,因為之前沒有接觸過後來百度了一下發現原來這個庫主要是用來實現一些比較複雜的動畫的。下面是官方的介紹,Lottie是Airbnb開源的一個支援Android、ios以及ReactNative,利用json檔案的方式快速的實現動畫效果的庫,接下來就介紹一下它的如何使用的。
最開始我們就去github上看看它的原始碼以及Demo:
以前我們在實現動畫的時候一般都有以下幾種方式:
- 使用幀動畫。這種方式就是多張圖片連續的切換,所以可想而知一個最大的弊端就是會導致最後的apk會非常的大。
- 使用Gif。gif的話可以實現很多複雜的動畫,但是我們知道Android本身是不支援gif的,而且還需要為各種螢幕的尺寸和解析度做適配的,還有一個很重要的問題就是gif也會導致apk非常大的。
- 使用程式碼實現,比如說補間動畫和屬性動畫來實現很多複雜的動畫,但是對於有些不擅長於寫動畫的童鞋來說是一個頭痛的問題。
為了解決上述等等各種問題,懶惰的人們就開發一款可以跨平臺的動畫框架,動畫的路徑資料就用一種通用的格式來記錄,然後中間的話就分別用對應的平臺來實現動畫的走動。所以這個時候Lottie就出現了。
設計師的工作(其實這邊我們可以不關心)
- 首先我們讓設計使用Adobe的Afeter Effects(簡稱AE)工具製作這個動畫。
然後需要在AE中安裝一個叫做Bodymovin的外掛,解壓縮之後只需要\build\extension\bodymovin.zxp這個檔案就可以
手動安裝plugin,以window系統而言,要先下載ExMan Command Line tool 並解壓縮,再把下載的bodymovin壓縮後的bodymovin-master/build/extension 目錄下的bodymovin.zxp這個檔案複製進去同一個資料夾。
去找cmd,並以系統管理員身份執行。
開啟 ExManCmd_win所在的路徑,進入ExManCmd_win的資料夾中
接著打 ExManCmd.exe /install bodymovin.zxp 就完成了
再來進入AE 後,可以在windows/extentions/bodymovin 找到外掛,開啟後按下Render 就完成了。 重點來了,這時會在你選的Destination Folder目錄中生成一個json格式的檔案,這個 json 檔案描述了該動畫的一些關鍵點的座標以及運動軌跡,然後再轉發給開發人員。
工程師的工作
首先我們需要在build.gradle 檔案引入動畫框架
dependencies { compile 'com.airbnb.android:lottie:2.0.0-beta4' }
根據平時的經驗我們都知道UI給我們的動畫檔案或者是資原始檔都會放到drawable目錄下去的,但是這次 UI 給我們的動畫檔案我們只能放到Assets目錄下的,並不能放到其他的目錄下,因為只有這樣子的框架才能更好的找到其路徑的。下面我們分別的來介紹三種方式載入動畫檔案。
1. Assets目錄預設載入
首先我們將動畫檔案放到默Assets目錄下,然後在layout佈局檔案中直接引用就可以了,其中fileName就是對應Assets目錄下的檔案的名字;loop true表示迴圈播放,false表示只播放一次; auto_play表示一開始就自動播放,設定false的話,就需要自己手動的呼叫 playAnimation() 來手動進行播放控制<com.airbnb.lottie.LottieAnimationView android:id="@+id/animation_view" android:layout_width="wrap_content" android:layout_height="wrap_content" app:lottie_fileName="data.json" app:lottie_loop="true" app:lottie_autoPlay="true" />
2. 從網路上直接獲取json資料進行載入
public void loadRemoteLottie() { Request request; try { request = new Request.Builder().url(url).build(); } catch (IllegalArgumentException e) { return; } if (client == null) { client = new OkHttpClient(); } client.newCall(request).enqueue(new Callback() { public void onFailure(Call call, IOException e) { } public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { try { JSONObject json = new JSONObject(response.body().string()); LottieComposition.Factory.fromJson(mResource, json, new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition lottieComposition) { animation_view_network.setProgress(0); animation_view_network.loop(true); animation_view_network.setComposition(composition); animation_view_network.playAnimation(); } }); } catch (JSONException e) { } } } }); }
我們可以通過獲取遠端json資料的這種格式來動態的配置應用裡面的動畫,這裡面有幾個要注意的問題:
- 這裡我們在不能再像以前樣子在layout中配置那些屬性,這個時候我們只需要在xml中寫一個簡單的佈局檔案就可,如果你再設定那些屬性的話,比如說你設定了自動播放和迴圈播放,但是你都還沒有載入到資源,所以這個時候會有問題的。
- 這種通過獲取json字串來實現動畫的方式,裡面不能包含有圖片,比如UE在做動畫的時候有時候可能會帶有圖片的(特殊要求,比如說有些json不能實現的複雜的圖片),這個時候如果還是通過這種方式再去載入的話,它會找不到路徑的。
3. 從本地載入帶有圖片的檔案
有的時候UI做的AE動畫檔案中可能會帶有圖片的,這個時候如果你再使用原來那種通過獲取json字串的方式去獲取本地檔案的字串的時候,這個時候會報一個內部的 You must set an images folder before loading an image. Set it with LottieComposition#setImagesFolder or LottieDrawable#setImagesFolder 因為它有圖片,需要我們根據設定的路徑去尋找圖片並且渲染出來,這個後期我們會慢慢的分析。
private void loadLocal() {
String sdcardPath = Environment.getExternalStorageDirectory();
String path = sdcardPath + "/test_animation/newtest/data.json";
final String imageFolder = sdcardPath + "/test_animation/newtest/images/";
//1. 開始的時候我們需要設定它的圖片儲存的地方
animation_view_network.setImageAssetsFolder(imageFolder);
File file = new File(path);
if(file.exists()) {
try {
FileInputStream fis = new FileInputStream(file);
LottieComposition.Factory.fromInputStream(this, fis,
new OnCompositionLoadedListener() {
@Override
public void onCompositionLoaded(LottieComposition lottieComposition) {
setComposition(lottieComposition);
}
});
//2. 然後呼叫該方法分別的去獲取對應圖片的地址,然後轉化為Bitmap
animation_view_network.setImageAssetDelegate(new ImageAssetDelegate() {
@Override
public Bitmap fetchBitmap(LottieImageAsset lottieImageAsset) {
String path = imageFolder + lottieImageAsset.getFileName();
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = true;
opts.inDensity = 160;
Bitmap bitmap = BitmapFactory.decodeFile(path, opts);
return bitmap;
}
});
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
本次我們只是對Lottie Android做一個最基本如何使用它,但是我們學習一個框架的目的不僅僅只是為了學會使用它,更關鍵的是如何去學習它的思想以及一些好的程式碼規劃。比如說對於本框架來說,我們的目的就是先弄清楚它裡面的實現邏輯以及一些好的程式碼規範的,這樣子我們以後也可以寫出一個屬於自己的框架。下面將會結合官方的例子以及程式碼將程式碼和demo放在一起,然後放在csdn上,感興趣的同學可以在上面下載。