移動(dòng)端幀動(dòng)畫神來(lái)之筆 Lottie (iOS:從Json到Animation)

Lottie 簡(jiǎn)介

Lottie剛出來(lái)兩個(gè)月的時(shí)候,我們正好想尋找一個(gè)可擴(kuò)展的方案支持項(xiàng)目的2D幀動(dòng)畫需求,同事介紹下調(diào)研了Lottie。看官網(wǎng)Demo里各種酷炫的矢量動(dòng)畫,瞬間被驚艷到。想象一下平時(shí)寫復(fù)雜動(dòng)畫的痛苦: 一堆hard code, 被設(shè)計(jì)師各種追著調(diào)參數(shù)看效果。還有更復(fù)雜的平面動(dòng)畫,可能就直接上GIF,可使用 Gif 占用空間較大,而且需要為各種屏幕尺寸、分辨率做適配,因?yàn)?Android 沒(méi)有提供原生 Gif 的 api 支持,所以這種方案還會(huì)遇到兼容性問(wèn)題。另一種是用幀動(dòng)畫,但是幀動(dòng)畫占用空間比 Gif 還要大的多,也需要做適配。所以Lottie就粉墨登場(chǎng)了。

screens_1

Lottie做什么?

使用Lottie開發(fā)的流程是: 設(shè)計(jì)師在AE中設(shè)計(jì)完成你的動(dòng)畫,通過(guò)bodymoving插件導(dǎo)出紀(jì)錄動(dòng)畫信息的JSON文件,然后開發(fā)人員使用 Lottie 的Android,iOS,React Native apps開源動(dòng)畫庫(kù)讀取這份JSON文件, 解析動(dòng)畫結(jié)構(gòu)和參數(shù)信息并渲染。

image.png

相關(guān)工具:

  • Adobe AE CC 2017版本
  • ZXP installer AE插件安裝工具,先安裝這個(gè)。
  • bodymovin AE動(dòng)畫導(dǎo)出為JSON文件的插件。
    • 下載ZIP文件,解壓得到bodymovin.zxp
    • 打開ZXP in staller, 將bodymovin.zxp拖進(jìn)去安裝。


      image.png

Lottie的優(yōu)點(diǎn)

  1. 設(shè)計(jì)即所見: 設(shè)計(jì)師用AE設(shè)計(jì)好動(dòng)畫后直接導(dǎo)出Json文件,Lottie 解析Json文件后調(diào)Core Animation的API繪制渲染。還原度更好,開發(fā)成本更低。

  2. 跨平臺(tái): 支持iOS、Android、React Native。

  3. 性能:Lottie對(duì)于從AE導(dǎo)出的Json文件,用Core Animation做矢量動(dòng)畫, 性能較佳。Lottie 對(duì)解析后的數(shù)據(jù)模型有內(nèi)存緩存。但是對(duì)多圖片幀動(dòng)畫,性能比較差。

  4. 支持動(dòng)畫屬性多:比起臉書的Keyframes,Lottie支持了更多AE動(dòng)畫屬性,比如Mask, Trim Paths,Stroke (shape layer)等。

  5. 包大小,相比動(dòng)輒上百K的幀動(dòng)畫,Json文件包大小很小。有圖片資源的情況下,同一張圖片也可以被多個(gè)圖層復(fù)用,而且運(yùn)行時(shí)內(nèi)存中只有一個(gè)UIImage對(duì)象(iOS)。

庖丁解牛: Lottie iOS 的實(shí)現(xiàn)

Lottie動(dòng)畫庫(kù)主要由兩個(gè)部分組成:解析渲染

解析

復(fù)雜的AE動(dòng)畫用bodymoving導(dǎo)出后,其復(fù)雜的圖層關(guān)系、動(dòng)畫屬性都會(huì)映射到一串Json中。Lottie第一步要做的就是將data.json中的結(jié)構(gòu)化數(shù)據(jù)解析成對(duì)應(yīng)的模型類。
比如:AffterEffect新建項(xiàng)目時(shí)新建一個(gè)合成, Composition需要指定起始幀時(shí)間,終止時(shí)間 ,幀率:

導(dǎo)出成data.json后,對(duì)應(yīng)的字段:

代碼里L(fēng)OTComposition模型類對(duì)應(yīng)的屬性:

@property (nonatomic, readonly) NSNumber *startFrame;   // 起始幀
@property (nonatomic, readonly) NSNumber *endFrame;     // 結(jié)束幀
@property (nonatomic, readonly) NSNumber *framerate;    // 幀率

下面是Lottie里簡(jiǎn)略的數(shù)據(jù)模型類關(guān)系圖:

image.png

LOTComposition是整個(gè)數(shù)據(jù)模型,有點(diǎn)像個(gè)大畫布。它有屬性assetGroup(資源) 。如果AE動(dòng)畫有用到png圖片,bodymovin導(dǎo)出的文件后,image文件夾下會(huì)有對(duì)應(yīng)的png圖片 。每張圖的信息抽象在一個(gè)LOTAsset對(duì)象里,主要屬性是本地路徑(供加載用)、referenceID(跟對(duì)應(yīng)圖層做關(guān)聯(lián)) 。LOTComposition對(duì)象還有一個(gè)屬性是,layerGroup(圖層組),是一個(gè)圖層數(shù)組 。所有酷炫動(dòng)畫拆解后不過(guò)只是不同圖層、不同屬性在同一時(shí)刻的變化效果。 對(duì)應(yīng)AE軟件,圖層數(shù)據(jù)模型紀(jì)錄了一些屬性幀動(dòng)畫信息,比如屬性動(dòng)畫位移(position)、縮放(scale)、透明度(opacity)、旋轉(zhuǎn)(rotation)信息。這些信息被解析后存儲(chǔ)在一些屬性類里,存初始時(shí)間、結(jié)束時(shí)間、幀率、插值用的某幀對(duì)應(yīng)的值、時(shí)間函數(shù)等。用他們直接構(gòu)造iOS 的Core Animation 動(dòng)畫對(duì)象。

比如這里有個(gè)動(dòng)畫,內(nèi)圓點(diǎn)有透明度漸變動(dòng)畫(由0到1,再?gòu)?到0),導(dǎo)出后屬性動(dòng)畫都在"ks"字典中,其中透明度又在“o”這個(gè)字典中。Lottie解析后Layer會(huì)存一個(gè)LOTAnimatableNumberValue對(duì)象,紀(jì)錄動(dòng)畫信息。如下圖:

7月-19-2017 15-14-46.gif

image.png

這些屬性動(dòng)畫數(shù)據(jù)在Lottie里都用類似的對(duì)象存著,并提供了轉(zhuǎn)化為CAKeyframeAnimation的接口。

image.png

如上類圖,LOTLayer 還有叫shapes的數(shù)組,存了一堆LOTShapeGroup對(duì)象,這啥呢?其實(shí)是在AE中有個(gè)Shape的概念,是顏色、形狀、透明度、等一些屬性的組合.

還是上面那個(gè)動(dòng)畫為例子,內(nèi)圓點(diǎn)形狀和顏色在 ae屬性和json文件表示:


image.png
image.png

渲染

解析好圖層結(jié)構(gòu)數(shù)據(jù)和動(dòng)畫參數(shù), Lottie-iOS調(diào)用Core Animation建圖層數(shù)和動(dòng)畫渲染。整個(gè)視圖有一個(gè)叫_childContainerLayer的圖層作為容器圖層,也是圖層樹的根節(jié)點(diǎn),開始根據(jù)數(shù)據(jù)往上添加子Layer. 比如上面例子的動(dòng)畫, 有1個(gè)合成,2個(gè)圖層。構(gòu)建圖層樹時(shí),先根據(jù)LOTComposition模型數(shù)據(jù)創(chuàng)建LOTCompositionLayer對(duì)象,作為第一個(gè)子圖層;然后LOTCompositionLayer 再根據(jù)LOTComposition中的layers數(shù)組創(chuàng)建對(duì)應(yīng)的LOTLayerView圖層2個(gè)。

image.png

其中LOTLayerView會(huì)負(fù)責(zé),用之前解析出來(lái)的屬性動(dòng)畫對(duì)象,構(gòu)建動(dòng)畫組CAAnimationGroup。

  NSMutableDictionary *keypaths = [NSMutableDictionary dictionary];
  if (_layerModel.opacity) {
    [keypaths setValue:_layerModel.opacity forKey:@"opacity"];
  }
  if (_layerModel.position) {
    [keypaths setValue:_layerModel.position forKey:@"position"];
  }
  if (_layerModel.anchor) {
    [keypaths setValue:_layerModel.anchor forKey:@"anchorPoint"];
  }
  if (_layerModel.scale) {
    [keypaths setValue:_layerModel.scale forKey:@"transform"];
  }
  if (_layerModel.rotation) {
    [keypaths setValue:_layerModel.rotation forKey:@"sublayerTransform.rotation"];
  }
  if (_layerModel.positionX) {
    [keypaths setValue:_layerModel.positionX forKey:@"position.x"];
  }
  if (_layerModel.positionY) {
    [keypaths setValue:_layerModel.positionY forKey:@"position.y"];
  }
    
  _animation = [CAAnimationGroup LOT_animationGroupForAnimatablePropertiesWithKeyPaths:keypaths];
  
  if (_animation) {
    [_childContainerLayer addAnimation:_animation forKey:@"LottieAnimation"];
  }

這是渲染相關(guān)的類簡(jiǎn)圖:它還支持mask跟裁剪等其他效果。


image.png

使用中的痛點(diǎn):

  1. 支持AE動(dòng)畫屬性有限,有的AE動(dòng)畫效果bodymoving無(wú)法導(dǎo)出,還有一些缺陷bodymoving導(dǎo)出的矢量動(dòng)畫無(wú)法支持。比如尚未看到支持陰影的效果
  2. 有些矢量動(dòng)畫 ,對(duì)設(shè)計(jì)師的要求比較高。而且蠻多設(shè)計(jì)師不會(huì)使用AE。

資源網(wǎng)站

https://www.lottiefiles.com/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容