從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

wutongke發表於2017-03-03

Lottie是最近Airbnb開源的動畫專案,支援Android、iOS、ReactNaitve三個平臺,相關背景介紹可以參考之前的文章Airbnb開源炫酷動畫庫Lottie(譯)-看看Airbnb的工程師怎麼說。本文分析主要Lottie把json檔案轉為動畫的思路和原始碼實現。

文章首先介紹Lottie的基本使用,然後分析把json檔案對映到動畫的實現思路,最後分析Lottie的原始碼實現,這裡分析的是Lottie-Android。

基本用法

與使用相關的只有三個類檔案:LottieAnimationView、LottieComposition、LottieDrawable,所以Lottie使用起來特別簡單(需要注意Lottie支援API16及以上)。
最簡單的使用方式是在xml中增加LottieAnimationView:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

"Logo/LogoSmall.json"是需要載入的動畫資料路徑,根目錄是assets目錄。

也可以通過程式碼設定動畫資料json路徑:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

然後在程式碼中控制動畫播放或者新增監聽事件:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

Lottie提供了LottieDrawable可以使用:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

可以看到Lottie使用起來非常簡單,我們之後就從以上用到的LottieAnimationView、LottieComposition、LottieDrawable入手來分析下Lottie動畫的實現原理。

思路分析

我們先從底層思考下如何在螢幕上繪製動畫,最簡單的方式是把動畫分為多張圖片,然後通過週期替換螢幕上繪製的圖片來形成動畫,這種暴力的方式非常簡單,但缺點明顯,很耗記憶體,動畫播放中前後兩張替換的圖片在很多元素並沒有變化,重複的內容浪費了空間。

為了提高空間利用率,可以把圖片中的元素進行拆分,使用過photoshop的同學知道,其實在處理一張圖片時,可以把一張複雜的圖片使用多個圖層來表示,每個圖層上展示一部分內容,圖層中的內容也可以拆分為多個元素。拆分元素之後,根據動畫需求,可以單獨對圖層,甚至圖層中的元素設定平移、旋轉、收縮等動畫。

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

Lottie使用json檔案來作為動畫資料來源,json檔案是通過Bodymovin外掛匯出的,檢視sample中給出的json檔案,其實就是把圖片中的元素進行來拆分,並且描述每個元素的動畫執行路徑和執行時間。Lottie的功能就是讀取這些資料,然後繪製到螢幕上。

現在思考如果我們拿到一份json格式動畫如何展示到螢幕上。首先要解析json,建立資料到物件的對映,然後根據資料物件建立合適的Drawable繪製到View上,動畫的實現可以通過操作讀取到的元素完成。

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

原始碼分析

1. json檔案到物件的對映

Lottie使用LottieComposition來作為After Effects的資料物件,即把json檔案對映到LottieCompositionLottieComposition中提供瞭解析json的靜態方法:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

我們看下LottieComposition都有哪些成員變數,這些成員變數描述了After Effects中的動畫。

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

可以看到startFrame、endFrame、duration、scale等都是動畫中常見的。我們看下List<Layer>,看名字就是對映拆分後的圖層資料:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

Layer 中完成layer的json資料解析:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

2. 資料物件到Drawable的對映

AnimatableLayer 繼承自 Drawable,我們看下它的子類:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

其中LayerView對應著Layer資料,Layer中有

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

對應的LayerView中有
從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

可以簡單地理解為ViewGroup中可以包含ViewGroup或者View,但其實整個Lottie實現的動畫都是繪製在一個View LottieAnimationView上。

AnimatableLayer 的其它子類如 ShapeLayer,RectLayouer等作為 LayerViewList<AnimatableLayer>的元素。

3. 繪製

LottieAnimationView 繼承自 AppCompatImageView,封裝了一些動畫的操作,如:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

具體的繪製時委託為 LottieDrawable 完成的,我們看下 LottieDrawable 中的 draw() 方法:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

LottieDrawable 繼承自AnimatableLayer,其draw()方法如下:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

可以看到先繪製了本層的內容,然後開始繪製包含的layers的內容:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

這個過程於介面中ViewGroup巢狀繪製類似。

實現分析

上面我們根據動畫繪製的思路分析了下Lottie實現機制,下面從正面來捋一下程式的執行過程:

  1. 建立LottieAnimationView lottieAnimationView
  2. 建立LottieDrawable lottieDrawable
  3. 使用LottieComposition中的靜態方法解析json檔案建立LottieComposition lottieComposition,這個過程中已經建立來多個Layer物件。
  4. lottieDrawable.setComposition(lottieComposition)

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

先清理之前的資料,然後開始buildLayersForComposition,即根據lottieComposition建立多個layerView,此時已經建立好了多個Drawable,並通過List建立的為以lottieDrawable為根的一個drawable樹。

  1. lottieAnimationView.setImageDrawable(lottieDrawable)

  2. lottieAnimationView.playAnimation()

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

直接委託給了lottieDrawablelottieDrawable中有private final ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

重點看下setProgress方法

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

呼叫了private final List<KeyframeAnimation<?>> animations = new ArrayList<>()setProgress

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析

onValueChanged時,各個建立好的Drawable會根據需求進行重繪,達到動畫的效果。

Lottie把動畫從View的動效轉移到了Drawable上。

Lottie的效能

可以看到Lottie把json描述的動畫資料對映到Drawable之後,實現動畫時用到了ValueAnimator,在動畫更新時使用Drawable而非View,個人感覺在不需要互動時Drawable顯然比View更加輕量。以下是Lottie效能的官方的說明:

  1. 如果沒有mask和mattes,那麼效能和記憶體非常好,沒有bitmap建立,大部分操作都是簡單的cavas繪製。
  2. 如果存在mattes,將會建立2~3個bitmap。bitmap在動畫載入到window時被建立,被window刪除時回收。所以不宜在RecyclerView中使用包涵mattes或者mask的動畫,否則會引起bitmap抖動。除了記憶體抖動,mattes和mask中必要的bitmap.eraseColor()和canvas.drawBitmap()也會降低動畫效能。對於簡單的動畫,在實際使用時效能不太明顯。
  3. 如果在列表中使用動畫,推薦使用快取LottieAnimationView.setAnimation(String, CacheStrategy) 。

歡迎關注公眾號wutongke,每天推送移動開發前沿技術文章:

從 json 檔案到炫酷動畫 - Lottie 實現思路和原始碼分析
wutongke

推薦閱讀:

Airbnb開源炫酷動畫庫Lottie(譯)-看看Airbnb的工程師怎麼說

相關文章