如何理解Android屬性動(dòng)畫

和之前的文章一樣,沒有使用代碼進(jìn)行講解,所以讀者閱讀起來可能有點(diǎn)吃力。我建議閱讀的時(shí)候,結(jié)合源碼,效果更佳。文章必定會(huì)有疏漏的地方,讀者在閱讀過程如發(fā)現(xiàn),請(qǐng)務(wù)必指正,不甚感激!

動(dòng)畫是什么?

這或許是個(gè)簡(jiǎn)單的問題,很多人都會(huì)回答說“動(dòng)畫就是一幀幀靜態(tài)畫面的連續(xù)播放”。這樣的回答表明,動(dòng)畫的組成元素是每一幀畫面。我們看到的2D動(dòng)畫就是這樣。然而我們發(fā)現(xiàn)在電影院,2D動(dòng)畫幾乎已經(jīng)絕跡,普遍都是畫質(zhì)更為逼真,人物表情更為豐富的CG動(dòng)畫。制作CG動(dòng)畫有一個(gè)重要的步驟就是--建模,比如人物,花草,建筑物等等都是被獨(dú)立看待的一個(gè)個(gè)模型。我們以CG動(dòng)畫的角度看,動(dòng)畫的組成元素是一個(gè)個(gè)獨(dú)立的模型。每個(gè)模型都有本身的屬性,比如頭發(fā)的弧度,手臂的位置,瞳孔的顏色等等。當(dāng)我們把動(dòng)畫以幀的方式進(jìn)行分割,實(shí)際上就割裂了屬性變化的連續(xù)性。而CG動(dòng)畫則是以事物屬性為關(guān)注點(diǎn),并且注重屬性變化的連續(xù)性,所以效果就更加逼真靈動(dòng)。

從2D動(dòng)畫到CG動(dòng)畫,是技術(shù)的進(jìn)步,也是認(rèn)知的提升。Android動(dòng)畫框架也經(jīng)歷了這樣的轉(zhuǎn)變。

Android早期提供的動(dòng)畫框架被稱為幀動(dòng)畫,就像2D動(dòng)畫一樣,所以也有著2D動(dòng)畫的缺點(diǎn)--動(dòng)畫效果卡頓。這使得Android在3.0推出了全新的動(dòng)畫框架--屬性動(dòng)畫。屬性動(dòng)畫與CG動(dòng)畫的核心理念是一樣的--所動(dòng)畫的是屬性,而不是幀。Androd官方把屬性動(dòng)畫框架的開發(fā)稱之為--黃油計(jì)劃,原因顯而易見,就是讓動(dòng)畫像黃油一樣順滑。

我在此談的就是屬性動(dòng)畫。

動(dòng)畫回調(diào)何時(shí)執(zhí)行?

在回答這個(gè)問題之前先談?wù)勚骶€程。主線程又稱UI線程,主要作用是處理交互事件,執(zhí)行界面繪制等功能。每個(gè)人都能拿這個(gè)回答去搪塞別人,回答問題的人未必在頭腦中建立了主線程運(yùn)轉(zhuǎn)機(jī)制的模型。線程交互的基本模型就是生產(chǎn)者-消費(fèi)者模型。在這個(gè)模型中工作線程將生產(chǎn)的Runnable,不斷發(fā)送到主線程供其消費(fèi)。主線程的Run方法存在一個(gè)死循環(huán),在這個(gè)死循環(huán)中,它不斷處理別人生成的Runnable.。投遞給主線程的Runnable一般分為兩類。一類是系統(tǒng)產(chǎn)生的事件,如交互事件,四大組件的生命周期回調(diào);另一類事件是程序自身產(chǎn)生的--那些post系列方法發(fā)送的Runnable,動(dòng)畫事件回調(diào),界面繪制事件。四大組件的生命周期回調(diào)我們不談及,他是由系統(tǒng)操控的。這些Runnable就是胡亂的塞到主線程的消息隊(duì)列中的嗎?顯然不是,絕對(duì)不是!

問題來了,這些Runnable如何在主線程中進(jìn)行組織?

所謂組織就是給這些Runnable排個(gè)序,排序標(biāo)準(zhǔn)有兩個(gè):一是這些Runnale之間固有的先后順序,比如交互事件的處理就應(yīng)該在繪制事件前面,因?yàn)槲覀冎挥杏?jì)算了手移動(dòng)了多少距離,才能決定屏幕中的控件移動(dòng)多少距離;二是以時(shí)間排序,比如postDelayed方法就會(huì)延遲Runnable的執(zhí)行。這些事件在主線程的處理順序是:交互事件回調(diào)--動(dòng)畫事件回調(diào)--界面繪制。Android系統(tǒng)每隔16ms發(fā)出VSYNC信號(hào),接收到VSYNC信號(hào),主線程會(huì)依次執(zhí)行交互事件回調(diào),動(dòng)畫事件回調(diào),最后觸發(fā)UI繪制。在Android中實(shí)現(xiàn)Runnable調(diào)度組織功能的是Choreographer,它為以上三類事件的分別維護(hù)了一個(gè)列表。

屬性動(dòng)畫如何將動(dòng)畫回調(diào)事件交給Choreographer?

我能想到最簡(jiǎn)陋的動(dòng)畫效果實(shí)現(xiàn)就是,一個(gè)放映員不斷切換幻燈片,只要放映員切換速度足夠快,也能達(dá)到"動(dòng)畫"的效果。這里有個(gè)重要的角色就是切換幻燈片的放映員。Android的屬性動(dòng)畫也需要這樣一個(gè)放映員,我們稱這個(gè)放映員為動(dòng)畫引擎。

Android屬性動(dòng)畫的引擎只有一個(gè),所有的動(dòng)畫都由這個(gè)引擎調(diào)度。這樣做的好處是所有動(dòng)畫分享相同的時(shí)間,那么動(dòng)畫之間就能同步。在Android中動(dòng)畫引擎的實(shí)現(xiàn)類是AnimationHandler--組織編排所有動(dòng)畫的執(zhí)行(每個(gè)動(dòng)畫的啟動(dòng)時(shí)間不一樣,另外有的動(dòng)畫會(huì)延遲執(zhí)行),根據(jù)動(dòng)畫時(shí)間計(jì)算動(dòng)畫值。AnimationHandler會(huì)拿到Choreographer的一個(gè)實(shí)例,并將自己放置到Choreographer所維護(hù)的動(dòng)畫事件列表中,隨著每一次VSYNC信號(hào)的到來,而得到執(zhí)行。

為什么屬性動(dòng)畫會(huì)順滑?

之前提到了Android系統(tǒng)會(huì)每隔16ms發(fā)出VSYNC信號(hào)。為什么是16ms?因?yàn)槿祟愐曈X能接受到畫面變化的時(shí)間就是16ms,當(dāng)大于16ms,人就會(huì)感覺到畫面不連續(xù),我們稱為卡頓,所以Android會(huì)每隔16ms刷新一次畫面。一般的,我們?cè)趧?dòng)畫回調(diào)中修改了View的某些屬性,然后緊接著在View的繪制中應(yīng)用了了這些屬性,這一切都是在這16ms內(nèi)完成的,因而我們感覺到動(dòng)畫效果是順滑。

最后編輯于
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,034評(píng)論 25 709
  • 1. 前言 上一篇文章《Android Animation運(yùn)行原理詳解》介紹了插間動(dòng)畫的原理,而Android3....
    SparkInLee閱讀 14,163評(píng)論 5 52
  • 為了理解App是如何進(jìn)行渲染的,我們必須了解手機(jī)硬件是如何工作,那么就必須理解什么是VSYNC。 在講解VSYNC...
    Viking_Den閱讀 5,134評(píng)論 1 8
  • 有什么料? 從這篇文章中你能獲得這些料: 知道setContentView()之后發(fā)生了什么? 知道Android...
    CoorChice閱讀 26,952評(píng)論 42 312
  • 年齡越來越大,經(jīng)歷越來越多,人變得成熟了,但能夠放心說出來的話,可以聊得來的人也越來越少。認(rèn)識(shí)的人有很多,通訊錄里...
    驀荻閱讀 337評(píng)論 0 0

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