iOS動畫原理--模型樹和呈現(xiàn)樹

模型樹和呈現(xiàn)樹

CoreAnimation作為一個(gè)復(fù)合引擎,將不同的視圖層組合在屏幕中,并且存儲在圖層樹中,向我們展示了所有屏幕上的一切。
整個(gè)過程其實(shí)經(jīng)歷了三個(gè)樹狀結(jié)構(gòu),才顯示到了屏幕上:模型樹-->呈現(xiàn)樹-->渲染樹,如圖:

通常,我們操作的是模型樹,在重繪周期最后,我們會將模型樹相關(guān)內(nèi)容(層次結(jié)構(gòu)、圖層屬性和動畫)序列化,通過IPC傳遞給專門負(fù)責(zé)屏幕渲染的渲染進(jìn)程。渲染進(jìn)程拿到數(shù)據(jù)并反序列化出樹狀結(jié)構(gòu)--呈現(xiàn)樹。這個(gè)呈現(xiàn)圖層實(shí)際上是模型圖層的復(fù)制,但是它的屬性值代表了在任何指定時(shí)刻當(dāng)前外觀效果。換句話說,你可以通過呈現(xiàn)圖層的值來獲取當(dāng)前屏幕上真正顯示出來的值。

我們可以通過CALayer的-presentationLayer方法來訪問對應(yīng)的呈現(xiàn)樹圖層。注意呈現(xiàn)圖層僅僅當(dāng)圖層首次被提交(就是首次第一次在屏幕上顯示)的時(shí)候創(chuàng)建,所以在那之前調(diào)用-presentationLayer將會返回nil。你可能注意到有一個(gè)叫做–modelLayer的方法。在呈現(xiàn)圖層上調(diào)用–modelLayer將會返回它正在呈現(xiàn)所依賴的CALayer。通常在一個(gè)圖層上調(diào)用-modelLayer會返回–self(實(shí)際上我們已經(jīng)創(chuàng)建的原始圖層就是一種數(shù)據(jù)模型)。

一個(gè)移動的圖層是如何通過數(shù)據(jù)模型呈現(xiàn)的

大多數(shù)情況下,你不需要直接訪問呈現(xiàn)圖層,你可以通過和模型圖層的交互,來讓Core Animation更新顯示。兩種情況下呈現(xiàn)圖層會變得很有用,一個(gè)是同步動畫,一個(gè)是處理用戶交互。

當(dāng)模型樹上帶有動畫特征時(shí),提交到渲染進(jìn)程后,渲染進(jìn)程會根據(jù)動畫特征,不斷修改呈現(xiàn)樹上的圖層屬性,并同時(shí)不斷的在屏幕上渲染出來,這樣我們就看到了動畫。

如果你想讓你做動畫的圖層響應(yīng)用戶輸入,你可以使用-hitTest:方法來判斷指定圖層是否被觸摸,這時(shí)候?qū)Τ尸F(xiàn)圖層而不是模型圖層調(diào)用-hitTest:會顯得更有意義,因?yàn)槌尸F(xiàn)圖層代表了用戶當(dāng)前看到的圖層位置,而不是當(dāng)前動畫結(jié)束之后的位置。

模型樹與呈現(xiàn)樹關(guān)系的比喻

在CALayer內(nèi)部,它控制著兩個(gè)屬性:presentationLayer(以下稱為P)和modelLayer(以下稱為M)。P只負(fù)責(zé)顯示,M只負(fù)責(zé)數(shù)據(jù)的存儲和獲取。我們對layer的各種屬性賦值比如frame,實(shí)際上是直接對M的屬性賦值,而P將在每一次屏幕刷新的時(shí)候回到M的狀態(tài)。比如此時(shí)M的狀態(tài)是1,P的狀態(tài)也是1,然后我們把M的狀態(tài)改為2,那么此時(shí)P還沒有過去,也就是我們看到的狀態(tài)P還是1,在下一次屏幕刷新的時(shí)候P才變?yōu)?。而我們幾乎感知不到兩次屏幕刷新之間的間隙,所以感覺就是我們一對M賦值,P就過去了。P就像是瞎子,M就像是瘸子,瞎子背著瘸子,瞎子每走一步(也就是每次屏幕刷新的時(shí)候)都要去問瘸子應(yīng)該怎樣走(這里的走路就是繪制內(nèi)容到屏幕上),瘸子沒法走,只能指揮瞎子背著自己走。可以簡單的理解為:一般情況下,任意時(shí)刻P都會回到M的狀態(tài)。而當(dāng)一個(gè)CAAnimation(以下稱為A)加到了layer上面后,A就把M從P身上擠下去了。現(xiàn)在P背著的是A,P同樣在每次屏幕刷新的時(shí)候去問他背著的那個(gè)家伙,A就指揮它從fromValue到toValue來改變值。而動畫結(jié)束后,A會自動被移除,這時(shí)P沒有了指揮,就只能大喊“M你在哪”,M說我還在原地沒動呢,于是P就順聲回到M的位置了。這就是為什么動畫結(jié)束后我們看到這個(gè)視圖又回到了原來的位置,是因?yàn)槲覀兛吹皆谝苿拥氖荘,而指揮它移動的是A,M永遠(yuǎn)停在原來的位置沒有動,動畫結(jié)束后A被移除,P就回到了M的懷里。
動畫結(jié)束后,P會回到M的狀態(tài)(當(dāng)然這是有前提的,因?yàn)閯赢嬕呀?jīng)被移除了,我們可以設(shè)置fillMode來繼續(xù)影響P),但是這通常都不是我們動畫想要的效果。我們通常想要的是,動畫結(jié)束后,視圖就停在結(jié)束的地方,并且此時(shí)我去訪問該視圖的屬性(也就是M的屬性),也應(yīng)該就是當(dāng)前看到的那個(gè)樣子。按照官方文檔的描述,我們的CAAnimation動畫都可以通過設(shè)置modelLayer到動畫結(jié)束的狀態(tài)來實(shí)現(xiàn)P和M的同步。

動畫實(shí)現(xiàn)方式

動畫,顧名思義就是動起來的畫面,任何使屏幕上的視圖隨時(shí)間不斷變化的技術(shù)都可以實(shí)現(xiàn)動畫。在iOS中,實(shí)現(xiàn)動畫的方式主要分兩大類:CoreAnimation動畫和非CoreAnimation動畫。

CoreAnimation動畫

CoreAnimation動畫,即基于事務(wù)的動畫,是最常見的動畫實(shí)現(xiàn)方式。動畫執(zhí)行者是專門負(fù)責(zé)渲染的渲染進(jìn)程,操作的是呈現(xiàn)樹。我們應(yīng)該盡量使用CoreAnimation來控制動畫,因?yàn)镃oreAnimation是充分優(yōu)化過的:

  1. 更高效的繪制

基于Layer的繪圖過程中,CoreAnimation通過硬件操作位圖(變換、組合等),產(chǎn)生動畫的速度比軟件操作的方式快很多。

基于View的繪圖過程中,view被改動時(shí)會觸發(fā)的drawRect:方法來重新繪制位圖,但是這種方式需要CPU在主線程執(zhí)行,比較耗時(shí)。而CoreAnimation則盡可能的操作硬件中已緩存的位圖,來實(shí)現(xiàn)相同的效果,從而減少了資源損耗。

How Core Animation draws content
  1. 更高效的動畫

在動畫過程中,CoreAnimation會通過硬件來一幀一幀的繪制。你所做的就是指定動畫的起點(diǎn)和終點(diǎn),其他的都讓CoreAnimation來做。當(dāng)然你也可以自定義動畫參數(shù),否則CoreAnimation會使用合適的默認(rèn)值。

非CoreAnimation動畫

非CoreAnimation動畫執(zhí)行者是當(dāng)前進(jìn)程,操作的是模型樹。常見的有定時(shí)器動畫和手勢動畫。定時(shí)器動畫是在定時(shí)周期觸發(fā)時(shí)修改模型樹的圖層屬性;手勢動畫是手勢事件(比如UIScrollView的didScrollView)觸發(fā)時(shí)修改模型樹的圖層屬性。兩者都能達(dá)到視圖隨著時(shí)間不斷變化的效果,即實(shí)現(xiàn)了動畫。

非CoreAnimation動畫動畫過程中實(shí)際上不斷改動的是模型樹,而呈現(xiàn)樹僅僅成了模型樹的復(fù)制品,狀態(tài)與模型樹保持一致。整個(gè)過程中,主要是CPU在主線程不斷調(diào)整圖層屬性、布局計(jì)算、提交數(shù)據(jù),沒有充分利用到CoreAnimation強(qiáng)大的動畫控制功能。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 書寫的很好,翻譯的也棒!感謝譯者,感謝感謝! iOS-Core-Animation-Advanced-Techni...
    錢噓噓閱讀 2,429評論 0 6
  • 在前面的學(xué)習(xí)中,我們討論了CoreAnimation除了動畫外可以做到的任何事情。但是動畫是CoreAni...
    小貓仔閱讀 1,619評論 0 0
  • 前言 本文只要描述了iOS中的Core Animation(核心動畫:隱式動畫、顯示動畫)、貝塞爾曲線、UIVie...
    GitHubPorter閱讀 3,736評論 7 11
  • CoreAnimation:Core Animation自身并不是一個(gè)繪圖系統(tǒng)。它只是一個(gè)負(fù)責(zé)在硬件上合成和操縱應(yīng)...
    YGoooooooooal閱讀 735評論 0 1
  • 前言 代碼每個(gè)人都會寫。但是,能把代碼寫的優(yōu)美,把結(jié)構(gòu)設(shè)計(jì)的足夠靈活,并且讓人贊嘆的人卻很少。尤其在中國這樣的大環(huán)...
    歐陽鋒閱讀 9,123評論 7 15

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