Lottie-android 學(xué)習筆記

引言

上周周會了解到Lottie這個開源項目,用json文件控制播放動畫缎玫,跟我之前做主題,用cocos-2dx引擎做游戲動畫思想有些類似努释,當時我就想體驗一下這個項目碘梢。

初識Lottie

首先看一組效果圖:


1-tLJBvcMic0P_toYRCuXZCQ (1).gif

感覺上面這個效果挺贊的,通過動作分解伐蒂,也能用Android提供的位移煞躬、旋轉(zhuǎn)、透明動畫組合,配合一些Interpolator(加速恩沛、減速在扰、彈跳)來實現(xiàn);但是下面這個用上面的方法進行動畫控制就太麻煩了(從效果看出雷客,下面的圖形都不是通過圖片控制的芒珠,全部都是通過path繪制的),當前也可以通過gif動畫來播放搅裙,不過gif動畫在低端手機可能會出現(xiàn)不流暢現(xiàn)象皱卓,再者就是gif圖片size較大,對包體大小有限制的App可能就不能接受:


Lottie介紹

介紹

Today, we’re happy to introduce our solution. Lottie is an iOS, Android, and React Native library that renders After Effects animations in real time, and allows native apps to use animations as easily as they use static assets. Lottie uses animation data exported as JSON files from an open-source After Effects extension called Bodymovin. The extension is bundled with a JavaScript player that can render the animations on the web. Since February of 2015, Bodymovin’s creator, Hernan Torrisi, has built a solid foundation by adding features and improvements to the plugin on a monthly basis. Our team (Brandon Withrow on iOS, Gabriel Peal on Android, Leland Richardson on React Native, and I on experience design) began our journey by building on top of Torrisi’s phenomenal work.

就是說Lottie支持Android部逮、iOS娜汁、React Native三個平臺,支持實時渲染After Effects動畫兄朋,使得app中使用動畫可以像使用靜態(tài)資源一樣簡單掐禁。 Lottie使用從Bodymovin(開源的After Effects插件)導(dǎo)出的json數(shù)據(jù)來作為動畫數(shù)據(jù)。

源碼分析

github上下載lottie-android源碼颅和,導(dǎo)入AS傅事,容易找到加載本地的動畫json文件入口方法:

void onLoadAssetClicked() {
animationView.cancelAnimation();
android.support.v4.app.DialogFragment assetFragment = ChooseAssetDialogFragment.newInstance();
assetFragment.setTargetFragment(this, RC_ASSET);
assetFragment.show(getFragmentManager(), "assets");
}

Lottie支持從本地加載json文件來實現(xiàn),也支持從網(wǎng)絡(luò)加載json格式的動畫數(shù)據(jù)來實現(xiàn)播放動畫(原理一樣)峡扩。加載完成后蹭越,會通過下面函數(shù)對動畫進行處理:

@Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
return;
}
switch (requestCode) {
case RC_ASSET:
final String assetName = data.getStringExtra(EXTRA_ANIMATION_NAME);
animationView.setImageAssetsFolder(assetFolders.get(assetName));
LottieComposition.Factory.fromAssetFileName(getContext(), assetName,
new OnCompositionLoadedListener() {
@Override
public void onCompositionLoaded(LottieComposition composition) {
setComposition(composition, assetName);
}
});
break;
case RC_FILE:
onFileLoaded(data.getData());
break;
case RC_URL:
break;
}
}

其中最核心的方法就是setComposition(composition, assetName),這個方法最核心的一句是animationView.setComposition(composition)教届;下面看一下這個方法的實現(xiàn):

/**
* Sets a composition.
* You can set a default cache strategy if this view was inflated with xml by
* using {@link R.attr#lottie_cacheStrategy}.
*/
public void setComposition(@NonNull LottieComposition composition) {
if (L.DBG) {
Log.v(TAG, "Set Composition \n" + composition);
}
lottieDrawable.setCallback(this);
boolean isNewComposition = lottieDrawable.setComposition(composition);
if (!isNewComposition) {
// We can avoid re-setting the drawable, and invalidating the view, since the composition
// hasn't changed.
return;
}
int screenWidth = Utils.getScreenWidth(getContext());
int screenHeight = Utils.getScreenHeight(getContext());
int compWidth = composition.getBounds().width();
int compHeight = composition.getBounds().height();
if (compWidth > screenWidth ||
compHeight > screenHeight) {
float xScale = screenWidth / (float) compWidth;
float yScale = screenHeight / (float) compHeight;
setScale(Math.min(xScale, yScale));
Log.w(L.TAG, String.format(
"Composition larger than the screen %dx%d vs %dx%d. Scaling down.",
compWidth, compHeight, screenWidth, screenHeight));
}
// If you set a different composition on the view, the bounds will not update unless
// the drawable is different than the original.
setImageDrawable(null);
setImageDrawable(lottieDrawable);
this.composition = composition;
requestLayout();
}

可以看到般又,通過composition的設(shè)置和請求requestLayout刷新界面,即可實現(xiàn)動畫的繪制巍佑,那么究竟composition和lottieDrawable是什么關(guān)系?以及他們是怎么實現(xiàn)動畫的繪制的寄悯?下面通過類圖來表達這一它們之間的關(guān)系:

lottie核心類圖.png

看起來比較復(fù)雜的動畫邏輯萤衰,其實實現(xiàn)起來并不是特別復(fù)雜,他們之間的關(guān)系很清晰:LottieAnimationView繼承AppCompatImageView猜旬,即可以當做一個增強版的ImageView來使用脆栋,只不過它里面包含了兩個核心成員:LottieDrawable和LottieComposition,所有的動畫播放和完成洒擦,都是通過控制這兩個核心成員來完成的椿争。

LottieComposition

負責解析Effects/Bodymovin產(chǎn)生的json動畫文件,并將其按照功能分類保存起來熟嫩∏刈伲可以這樣理解:LottieComposition就是動畫json數(shù)據(jù)的對象模型,通過LottieComposition,實現(xiàn)對動畫的分解和序列化椅邓,json動畫文件示例:

json.png

LottieDrawable

LottieDrawable就是根據(jù)LottieComposition保存的分層和序列動作柠逞,不停的進行繪制,實現(xiàn)連續(xù)動畫效果景馁,其核心邏輯如下:

@Override public void draw(@NonNull Canvas canvas) {
if (compositionLayer == null) {
return;
}
matrix.reset();
matrix.preScale(scale, scale);
compositionLayer.draw(canvas, matrix, alpha);
}

真正的實現(xiàn)在CompositionLayer的draw函數(shù)板壮,即:

@Override
public void draw(Canvas canvas, Matrix parentMatrix, int parentAlpha) {
if (!visible) {
return;
}
buildParentLayerListIfNeeded();
matrix.reset();
matrix.set(parentMatrix);
for (int i = parentLayers.size() - 1; i >= 0; i--) {
matrix.preConcat(parentLayers.get(i).transform.getMatrix());
}
int alpha = (int)
((parentAlpha / 255f * (float) transform.getOpacity().getValue() / 100f) * 255);
if (!hasMatteOnThisLayer() && !hasMasksOnThisLayer()) {
matrix.preConcat(transform.getMatrix());
drawLayer(canvas, matrix, alpha);
return;
}
rect.set(0, 0, 0, 0);
getBounds(rect, matrix);
intersectBoundsWithMatte(rect, matrix);
matrix.preConcat(transform.getMatrix());
intersectBoundsWithMask(rect, matrix);
rect.set(0, 0, canvas.getWidth(), canvas.getHeight());
canvas.saveLayer(rect, contentPaint, Canvas.ALL_SAVE_FLAG);
// Clear the off screen buffer. This is necessary for some phones.
clearCanvas(canvas);
drawLayer(canvas, matrix, alpha);
if (hasMasksOnThisLayer()) {
applyMasks(canvas, matrix);
}
if (hasMatteOnThisLayer()) {
canvas.saveLayer(rect, mattePaint, SAVE_FLAGS);
clearCanvas(canvas);
//noinspection ConstantConditions
matteLayer.draw(canvas, parentMatrix, alpha);
canvas.restore();
}
canvas.restore();
}

小結(jié)

真心覺得這個項目實在是太贊了,倒不是說這個項目在技術(shù)上有多高深合住,而是這個項目把軟件開發(fā)(或者說是編碼實現(xiàn)需求)的方法想得很極致:不是通過復(fù)雜的組合動畫和波動函數(shù)來控制绰精,而是通過對數(shù)據(jù)建模,通過設(shè)計師導(dǎo)出的數(shù)據(jù)透葛,在不同平臺上還原出效果笨使,完成設(shè)計稿與實現(xiàn)效果的完全還原(如果是通過系統(tǒng)動畫,很多情況下難以完全符合設(shè)計師的動畫要求)

  • 有了lottie获洲,設(shè)計師再也不用擔心開發(fā)不能達到預(yù)期效果了阱表,因為壓根不需要額外開發(fā)
  • 解放了開發(fā),啟迪了思想贡珊,我還需要學(xué)習一個最爬!

參考文章

https://github.com/airbnb/lottie-android
https://medium.com/airbnb-engineerin

1-tLJBvcMic0P_toYRCuXZCQ.gif
g/introducing-lottie-4ff4a0afac0e
http://www.reibang.com/p/d887c96684be

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市门岔,隨后出現(xiàn)的幾起案子爱致,更是在濱河造成了極大的恐慌,老刑警劉巖寒随,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糠悯,死亡現(xiàn)場離奇詭異,居然都是意外死亡妻往,警方通過查閱死者的電腦和手機互艾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讯泣,“玉大人纫普,你說我怎么就攤上這事『们” “怎么了昨稼?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拳锚。 經(jīng)常有香客問我假栓,道長,這世上最難降的妖魔是什么霍掺? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任匾荆,我火速辦了婚禮拌蜘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘棋凳。我一直安慰自己拦坠,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布剩岳。 她就那樣靜靜地躺著贞滨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拍棕。 梳的紋絲不亂的頭發(fā)上晓铆,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音绰播,去河邊找鬼骄噪。 笑死,一個胖子當著我的面吹牛蠢箩,可吹牛的內(nèi)容都是我干的链蕊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谬泌,長吁一口氣:“原來是場噩夢啊……” “哼滔韵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起掌实,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤陪蜻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后贱鼻,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宴卖,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年邻悬,在試婚紗的時候發(fā)現(xiàn)自己被綠了症昏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡父丰,死狀恐怖齿兔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情础米,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布添诉,位于F島的核電站屁桑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏栏赴。R本人自食惡果不足惜蘑斧,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧竖瘾,春花似錦沟突、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至庸论,卻和暖如春职辅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背聂示。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工域携, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鱼喉。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓秀鞭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親扛禽。 傳聞我的和親對象是個殘疾皇子锋边,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

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