版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2017.09.21 |
前言
app中好的炫的動(dòng)畫可以讓用戶耳目一新,為產(chǎn)品增色不少,關(guān)于動(dòng)畫的實(shí)現(xiàn)我們可以用基本動(dòng)畫、關(guān)鍵幀動(dòng)畫、序列幀動(dòng)畫以及基于CoreGraphic的動(dòng)畫等等,接下來這幾篇我就介紹下我可以想到的幾種動(dòng)畫繪制方法。具體Demo示例已開源到Github —— 刀客傳奇,感興趣的可以看我寫的另外幾篇。
1. 實(shí)現(xiàn)動(dòng)畫方式深度解析(一) —— 播放GIF動(dòng)畫(一)
2. 實(shí)現(xiàn)動(dòng)畫方式深度解析(二) —— 播放GIF動(dòng)畫之框架FLAnimatedImage的使用(二)
3. 實(shí)現(xiàn)動(dòng)畫方式深度解析(三) —— 播放序列幀動(dòng)畫(一)
4. 實(shí)現(xiàn)動(dòng)畫方式深度解析(四) —— QuartzCore框架(一)
5. 實(shí)現(xiàn)動(dòng)畫方式深度解析(五) —— QuartzCore框架之CoreAnimation(二)
Core Animation Basics
核心動(dòng)畫提供了一個(gè)通用的系統(tǒng),用于動(dòng)畫化您的app視圖和其他視覺元素。 核心動(dòng)畫不是您的app視圖的替代品。 相反,它是一種視圖集成的技術(shù),可以為動(dòng)畫內(nèi)容提供更好的性能和支持。 通過將視圖的內(nèi)容緩存到可以由圖形硬件直接操縱的位圖中來實(shí)現(xiàn)此行為。 在某些情況下,這種緩存行為可能需要您重新思考如何呈現(xiàn)和管理應(yīng)用程序的內(nèi)容,但大多數(shù)時(shí)候您使用Core Animation而無需知道它。 除了緩存視圖內(nèi)容之外,Core Animation還定義了一種指定任意可視內(nèi)容的方法,將該內(nèi)容與視圖集成,并將其與其他所有內(nèi)容一起動(dòng)畫化。
您可以使用Core Animation來動(dòng)畫更改應(yīng)用程序的視圖和視覺對(duì)象。 大多數(shù)更改涉及修改視覺對(duì)象的屬性。 例如,您可以使用Core Animation來動(dòng)態(tài)更改視圖的位置,大小或不透明度。 當(dāng)您進(jìn)行這樣的更改時(shí),核心動(dòng)畫將在當(dāng)前的屬性值和您指定的新值之間動(dòng)畫化。 通常不會(huì)使用Core Animation來代替視圖的內(nèi)容,每秒60次,如漫畫。 相反,您可以使用Core Animation將視圖的內(nèi)容移動(dòng)到屏幕上,將內(nèi)容淡入或淡出,對(duì)視圖應(yīng)用任意圖形轉(zhuǎn)換,或更改視圖的其他視覺屬性。
Layers Provide the Basis for Drawing and Animations
layer對(duì)象是組織在3D空間中的2D表面,并且是您使用Core Animation執(zhí)行的所有操作的核心。 像視圖一樣,layer管理有關(guān)其表面的幾何,內(nèi)容和視覺屬性的信息。 不同于視圖,layer沒有定義自己的外觀。 layer層僅管理位圖周圍的狀態(tài)信息。 位圖本身可以是您自己指定的視圖或您指定的固定圖像的結(jié)果。 因此,您在應(yīng)用程序中使用的main layer被認(rèn)為是模型對(duì)象,因?yàn)樗鼈冎饕芾頂?shù)據(jù)。 這個(gè)概念很重要,因?yàn)樗绊憚?dòng)畫的行為。
1. The Layer-Based Drawing Model - 基于Layer的繪畫模型
大多數(shù)圖層在您的應(yīng)用程序中沒有實(shí)際繪制。 相反,一個(gè)圖層捕獲您的應(yīng)用程序提供的內(nèi)容,并將其緩存在位圖中,該位圖有時(shí)稱為后備存儲(chǔ)。 當(dāng)您隨后更改圖層的屬性時(shí),您所做的就是更改與圖層對(duì)象關(guān)聯(lián)的狀態(tài)信息。 當(dāng)更改觸發(fā)動(dòng)畫時(shí),Core Animation會(huì)將圖層的位圖和狀態(tài)信息傳遞給圖形硬件,從而使用新信息渲染位圖的工作,如圖1-1所示。 在硬件中操作位圖產(chǎn)生比軟件更快的動(dòng)畫。
因?yàn)樗倏v一個(gè)靜態(tài)位圖,基于層的繪圖與更傳統(tǒng)的基于視圖的繪圖技術(shù)顯著不同。 使用基于視圖的繪圖,對(duì)視圖本身的更改通常會(huì)導(dǎo)致調(diào)用視圖的drawRect:方法以使用新參數(shù)重繪內(nèi)容。 但是以這種方式繪制是昂貴的,因?yàn)樗鞘褂弥骶€程上的CPU完成的。 Core Animation可以通過在硬件中操作緩存的位圖來實(shí)現(xiàn)相同或相似的效果,從而避免這種消耗。
雖然Core Animation盡可能使用緩存的內(nèi)容,但您的應(yīng)用仍然必須提供初始內(nèi)容并時(shí)時(shí)更新。 您的應(yīng)用程序有幾種方式為圖層對(duì)象提供內(nèi)容,這些內(nèi)容在提供圖層的內(nèi)容中有詳細(xì)描述 Providing a Layer’s Contents. 。
2. Layer-Based Animations - 基于layer的動(dòng)畫
層對(duì)象的數(shù)據(jù)和狀態(tài)信息與屏幕上該層內(nèi)容的視覺呈現(xiàn)分離。 這種去耦使得核心動(dòng)畫成為一種插入自己的方式,并將變化從舊的狀態(tài)值轉(zhuǎn)換為新的狀態(tài)值。 例如,更改圖層的position屬性會(huì)導(dǎo)致Core Animation將圖層從當(dāng)前位置移動(dòng)到新指定的位置。 與其他屬性類似的更改會(huì)導(dǎo)致適當(dāng)?shù)膭?dòng)畫。 下圖顯示了您可以在圖層上執(zhí)行的一些動(dòng)畫類型。 有關(guān)觸發(fā)動(dòng)畫的圖層屬性列表,請(qǐng)參閱動(dòng)畫屬性 Animatable Properties。
在動(dòng)畫過程中,Core Animation可以在硬件中為您提供所有的逐幀繪圖。 所有你需要做的是指定動(dòng)畫的開始和結(jié)束點(diǎn),并讓核心動(dòng)畫做其余的。 您還可以根據(jù)需要指定自定義定時(shí)信息和動(dòng)畫參數(shù); 但是,如果沒有,Core Animation提供了合適的默認(rèn)值。
有關(guān)如何啟動(dòng)動(dòng)畫和配置動(dòng)畫參數(shù)的更多信息,請(qǐng)參閱動(dòng)畫圖層內(nèi)容 Animating Layer Content。
Layer Objects Define Their Own Geometry - 定義自己幾何的層對(duì)象
layer的任務(wù)之一是管理其內(nèi)容的視覺幾何。 視覺幾何包含關(guān)于該內(nèi)容的界限,其在屏幕上的位置以及該layer是以任何方式旋轉(zhuǎn),縮放或變換的信息。 像視圖一樣,圖層layer具有框架和邊框,您可以使用它們來定位圖層及其內(nèi)容。 圖層還具有視圖沒有的其他屬性,例如錨點(diǎn),其定義了操作發(fā)生的位置。 指定層幾何的某些方面的方式也不同于如何為視圖指定信息。
1. Layers Use Two Types of Coordinate Systems - 使用兩種不同坐標(biāo)系統(tǒng)的圖層
圖層利用基于點(diǎn)的坐標(biāo)系和單位坐標(biāo)系來指定內(nèi)容的位置。 使用哪個(gè)坐標(biāo)系取決于正在傳達(dá)的信息的類型。 當(dāng)指定直接映射到屏幕坐標(biāo)的值時(shí)或者必須相對(duì)于另一層指定值時(shí),使用基于點(diǎn)的坐標(biāo),例如對(duì)于圖層的position屬性。 當(dāng)值不應(yīng)與屏幕坐標(biāo)相關(guān)時(shí)使用單位坐標(biāo),因?yàn)樗鄬?duì)于某個(gè)其他值。 例如,圖層的anchorPoint屬性指定了相對(duì)于圖層本身的邊界的點(diǎn),這可以改變。
基于點(diǎn)的坐標(biāo)最常見的用法是指定圖層的大小和位置,使用層的邊界和位置屬性。 邊界定義了圖層本身的坐標(biāo)系,并包含圖層在屏幕上的大小。 position屬性定義了圖層相對(duì)于其父坐標(biāo)系的位置。 盡管圖層具有frame屬性,但該屬性實(shí)際上是從邊界和位置屬性中的值導(dǎo)出的,并且使用的頻率較低。
層的邊界和框架矩形的方向總是與底層平臺(tái)的默認(rèn)方向相匹配。 下圖顯示了iOS和OS上邊界矩形的默認(rèn)方向。
上圖中要注意的一點(diǎn)是位置屬性位于圖層的中間。 該屬性是根據(jù)圖層的anchorPoint屬性中的值定義更改的幾個(gè)屬性之一。 錨點(diǎn)表示某些坐標(biāo)來源的點(diǎn),并在“錨點(diǎn)影響幾何操作 Anchor Points Affect Geometric Manipulations”中有更詳細(xì)的描述。
錨點(diǎn)是您使用單位坐標(biāo)系指定的幾個(gè)屬性之一。 核心動(dòng)畫使用單位坐標(biāo)來表示當(dāng)圖層的大小變化時(shí)其值可能會(huì)改變的屬性。 您可以將單位坐標(biāo)視為指定總可能值的百分比。 單位坐標(biāo)空間中的每個(gè)坐標(biāo)的范圍都為0.0到1.0。 例如,沿x軸,左邊緣在坐標(biāo)0.0處,右邊緣處于坐標(biāo)1.0。 沿y軸,單位坐標(biāo)值的方向取決于平臺(tái),如下圖所示。
注意:直到OS X 10.8,geometryFlipped屬性才能在需要時(shí)更改圖層y軸的默認(rèn)方向。 有時(shí)需要使用這個(gè)屬性來糾正一個(gè)層的方向。 例如,如果父視圖使用翻轉(zhuǎn)變換,則其子視圖(及其相應(yīng)圖層)的內(nèi)容通常會(huì)反轉(zhuǎn)。 在這種情況下,將子層的geometryFlipped屬性設(shè)置為YES可以解決問題。 在OS X 10.8及更高版本中,AppKit為您管理此屬性,您不應(yīng)該修改它。 對(duì)于iOS應(yīng)用程序,建議您不要使用geometryFlipped
屬性。
所有坐標(biāo)值,無論它們是點(diǎn)還是單位坐標(biāo)都被指定為浮點(diǎn)數(shù)。 使用浮點(diǎn)數(shù)允許您指定可能落在正常坐標(biāo)值之間的精確位置。 使用浮點(diǎn)值是很方便的,特別是在打印期間或當(dāng)繪制到Retina顯示屏上時(shí),其中一個(gè)點(diǎn)可能由多個(gè)像素表示。 浮點(diǎn)值允許您忽略底層設(shè)備分辨率,并僅以所需精度指定值。
2. Anchor Points Affect Geometric Manipulations - 錨點(diǎn)影響幾何操縱
與圖層的錨點(diǎn)相關(guān)的幾何相關(guān)操作發(fā)生,您可以使用圖層的anchorPoint
屬性進(jìn)行訪問。 當(dāng)處理層的位置或變換屬性時(shí),錨點(diǎn)的影響是最顯著的。 position屬性總是相對(duì)于圖層的錨點(diǎn)指定的,并且您應(yīng)用于圖層的任何轉(zhuǎn)換也會(huì)相對(duì)于錨點(diǎn)發(fā)生。
下圖演示了如何將錨點(diǎn)從其默認(rèn)值更改為不同的值會(huì)影響圖層的位置屬性。 即使圖層沒有在父層的邊界內(nèi)移動(dòng),將錨點(diǎn)從圖層的中心移動(dòng)到圖層的邊界起點(diǎn)也會(huì)改變position屬性的值。
下圖顯示了如何改變錨點(diǎn)影響應(yīng)用于圖層的變換。 當(dāng)您將旋轉(zhuǎn)變換應(yīng)用于圖層時(shí),旋轉(zhuǎn)將發(fā)生在錨點(diǎn)周圍。 因?yàn)槟J(rèn)情況下,錨點(diǎn)被設(shè)置在層的中間,所以通常會(huì)產(chǎn)生你期望的那種旋轉(zhuǎn)行為。 但是,如果更改錨點(diǎn),旋轉(zhuǎn)結(jié)果將不同。
3. Layers Can Be Manipulated in Three Dimensions - 圖層可以在三維方向操作
每個(gè)層都有兩個(gè)變換矩陣,您可以使用它們來操縱圖層及其內(nèi)容。 CALayer
的transform
屬性指定要應(yīng)用于圖層及其嵌入的子圖層的轉(zhuǎn)換。 通常,當(dāng)您要修改圖層本身時(shí),您可以使用此屬性。 例如,您可以使用該屬性縮放或旋轉(zhuǎn)圖層或暫時(shí)更改其位置。 sublayerTransform屬性定義了僅適用于子層的附加轉(zhuǎn)換,最常用于向場(chǎng)景內(nèi)容添加透視視覺效果。
通過將坐標(biāo)值乘以數(shù)字矩陣來轉(zhuǎn)換操作,以獲得代表原始點(diǎn)的轉(zhuǎn)換版本的新坐標(biāo)。 因?yàn)镃ore Animation值可以在三維中指定,所以每個(gè)坐標(biāo)點(diǎn)都有四個(gè)必須乘以4×4矩陣的值,如下圖所示。 在Core Animation中,圖中的變換由CATransform3D類型表示。 幸運(yùn)的是,您不必直接修改此結(jié)構(gòu)的字段來執(zhí)行標(biāo)準(zhǔn)轉(zhuǎn)換。 核心動(dòng)畫提供了一套全面的函數(shù)用于創(chuàng)建縮放,轉(zhuǎn)換和旋轉(zhuǎn)矩陣以及進(jìn)行矩陣比較。 除了使用函數(shù)操縱變換之外,Core Animation還擴(kuò)展了鍵值編碼KVC支持,以允許您使用關(guān)鍵路徑修改變換。 有關(guān)可以修改的關(guān)鍵路徑的列表,請(qǐng)參閱CATransform3D密鑰路徑 CATransform3D Key Paths。
下圖顯示了您可以進(jìn)行的一些更常見的轉(zhuǎn)換的矩陣配置。 通過identity變換乘以任何坐標(biāo)返回完全相同的坐標(biāo)。 對(duì)于其他變換,如何修改坐標(biāo)完全取決于您更改的矩陣組件。 例如,要僅沿x軸轉(zhuǎn)換,您將為轉(zhuǎn)換矩陣的tx組件提供非零值,并將ty和tz值保留為0,對(duì)于旋轉(zhuǎn),您將提供目標(biāo)旋轉(zhuǎn)角度適當(dāng)?shù)恼液陀嘞抑怠?/p>
有關(guān)用于創(chuàng)建和操作變換的功能的信息,請(qǐng)參閱Core Animation Function Reference
。
Layer Trees Reflect Different Aspects of the Animation State - layer樹反映動(dòng)畫狀態(tài)的不同方面
使用Core Animation
的app有三組圖層layer對(duì)象,每套圖層對(duì)象在使您的app的內(nèi)容出現(xiàn)在屏幕上方面具有不同的作用:
模型層樹
(或簡(jiǎn)稱“層樹”)中的對(duì)象是您的應(yīng)用程序與之最相互影響的對(duì)象。 此樹中的對(duì)象是存儲(chǔ)任何動(dòng)畫的目標(biāo)值的模型對(duì)象。 無論何時(shí)更改圖層的屬性,都可以使用其中一個(gè)對(duì)象。展示樹
中的對(duì)象包含任何正在運(yùn)行的動(dòng)畫的飛行中值。 而層樹對(duì)象包含動(dòng)畫的目標(biāo)值,而呈現(xiàn)樹中的對(duì)象會(huì)反映當(dāng)前值在屏幕上顯示的值。 您不應(yīng)該修改此樹中的對(duì)象。 而是使用這些對(duì)象來讀取當(dāng)前的動(dòng)畫值,也許是從這些值開始創(chuàng)建一個(gè)新的動(dòng)畫。渲染樹
中的對(duì)象執(zhí)行實(shí)際動(dòng)畫,并且對(duì)Core Animation
是私有的。
每組圖層layer對(duì)象被組織成層次結(jié)構(gòu),如app中的視圖。 實(shí)際上,對(duì)于一個(gè)能夠?yàn)槠渌幸晥D啟用圖層的app,每個(gè)樹的初始結(jié)構(gòu)恰好匹配了視圖層次結(jié)構(gòu)。 但是,app可以根據(jù)需要向?qū)哟谓Y(jié)構(gòu)中添加額外的圖層layer對(duì)象(即與視圖無關(guān)的圖層)。 您可以在不需要視圖所有開銷的內(nèi)容的情況下優(yōu)化app的性能。 下圖顯示了在一個(gè)簡(jiǎn)單的iOS app中找到的圖層layer細(xì)分。 示例中的窗口包含一個(gè)內(nèi)容視圖,該視圖本身包含一個(gè)按鈕視圖和兩個(gè)獨(dú)立的圖層對(duì)象。 每個(gè)視圖都有一個(gè)相應(yīng)的圖層對(duì)象,它形成圖層層次結(jié)構(gòu)的一部分。
對(duì)于圖層layer樹中的每個(gè)對(duì)象,展示樹和渲染樹中都有一個(gè)匹配的對(duì)象,如下圖所示。 如前所述,app主要使用圖層layer樹中的對(duì)象,但有時(shí)可以訪問展示樹中的對(duì)象。 具體來說,訪問layer樹中的對(duì)象的 presentationLayer屬性會(huì)返回呈現(xiàn)樹中的相應(yīng)對(duì)象。 您可能希望訪問該對(duì)象以讀取動(dòng)畫中間的屬性的當(dāng)前值。
重要:只有當(dāng)動(dòng)畫在飛行中時(shí),才能訪問展示樹中的對(duì)象。 當(dāng)動(dòng)畫正在進(jìn)行時(shí),展示樹包含當(dāng)時(shí)在屏幕上顯示的圖層值。 此行為與圖層layer樹不同,圖層樹總是反映您代碼設(shè)置的最后一個(gè)值,相當(dāng)于動(dòng)畫的最終狀態(tài)。
The Relationship Between Layers and Views - 圖層和視圖的關(guān)系
圖層不能替代您的app的視圖,也就是說,您無法僅基于圖層layer對(duì)象創(chuàng)建可視界面。 layer層為您的view提供基礎(chǔ)部分。 具體來說,圖層使繪圖和動(dòng)畫視圖的內(nèi)容變得更加容易和有效,并且在執(zhí)行此操作時(shí)保持較高的幀速率。 但是,還是有很多事情層layer是不能做的。 層layer不能處理事件、繪制內(nèi)容、參與響應(yīng)者鏈或做許多其他事情。 因此,每個(gè)app仍然必須有一個(gè)或多個(gè)視圖來處理這些交互。
在iOS中,每個(gè)視圖都由相應(yīng)的圖層對(duì)象支持,但在OS X中,您必須確定哪些視圖應(yīng)具有圖層。 在OS X v10.8
及更高版本中,將圖層添加到所有視圖可能是有意義的。 但是,您不需要這樣做,并且在開銷不合理和不必要的情況下仍可禁用層。 圖層確實(shí)會(huì)增加應(yīng)用程序的內(nèi)存開銷,但是它們的優(yōu)勢(shì)往往超過劣勢(shì),因此在禁用層支持之前,最好測(cè)試應(yīng)用程序的性能。
為視圖啟用圖層支持時(shí),可以創(chuàng)建所謂的支持層的視圖。 在層次支持的視圖中,系統(tǒng)負(fù)責(zé)創(chuàng)建底層圖層對(duì)象,并保持該圖層與視圖同步。 所有iOS視圖都是層次支持的,OS X中的大多數(shù)視圖也是如此。 但是,在OS X中,您還可以創(chuàng)建一個(gè)圖層托管視圖,這是您自己提供圖層對(duì)象的視圖。 對(duì)于層次托管視圖,AppKit采用手動(dòng)管理層,不會(huì)修改它以響應(yīng)視圖更改。
注意:對(duì)于層次支持的視圖,建議您盡可能操縱視圖,而不是圖層。 在iOS中,視圖只是圍繞層對(duì)象的薄包裝,因此您對(duì)圖層進(jìn)行的任何操作通常都可以正常工作。 但是在iOS和OS X中都有這樣的情況,其中操縱圖層而不是視圖可能不會(huì)產(chǎn)生所需的結(jié)果。 盡可能地,本文件指出了這些陷阱,并嘗試提供方法來幫助您解決這些問題。
除了與視圖相關(guān)聯(lián)的圖層之外,還可以創(chuàng)建沒有相應(yīng)視圖的圖層對(duì)象。 您可以將這些獨(dú)立圖層對(duì)象嵌入到應(yīng)用程序中的任何其他圖層對(duì)象中,包括與視圖關(guān)聯(lián)的圖層對(duì)象。 通常使用獨(dú)立圖層對(duì)象作為特定優(yōu)化路徑的一部分。 例如,如果要在多個(gè)地方使用相同的圖像,則可以加載圖像一次,并將其與多個(gè)獨(dú)立圖層對(duì)象相關(guān)聯(lián),并將這些對(duì)象添加到圖層樹中。 每個(gè)層然后引用源圖像,而不是嘗試在內(nèi)存中創(chuàng)建該圖像的自己的副本。
有關(guān)如何為應(yīng)用程序的視圖啟用圖層支持的信息,請(qǐng)參閱Enabling Core Animation Support in Your App。 有關(guān)如何創(chuàng)建層對(duì)象層次結(jié)構(gòu)的信息,以及有關(guān)何時(shí)可以這樣做的提示,請(qǐng)參閱Building a Layer Hierarchy。
后記
未完,待續(xù)~~~