Core Animation編程指南

Core Animation編程指南

關(guān)于Core Animation


Core Animation自身并不是一個繪圖系統(tǒng)。它只是一個負責在硬件上合成和操縱應(yīng)用內(nèi)容的基礎(chǔ)構(gòu)件。Core Animation的核心是圖層對象,圖層對象用于管理和操控你的應(yīng)用內(nèi)容。圖層將捕獲的內(nèi)容放到一副位圖中,圖形硬件能夠非常容易的操控你的位圖。在大部分應(yīng)用中,圖層被作為一種管理視圖內(nèi)容的方式,但是你也可以創(chuàng)建標準的圖層,這取決于你自身的需要。

隱式動畫是一種從舊屬性值動畫到新屬性值的動畫形式。

該文檔為那些需要更全面的控制動畫效果或打算利用圖層提升繪圖性能的開發(fā)者.


Core Animation基礎(chǔ)


圖層是繪圖與動畫的基礎(chǔ)


基于圖層的繪圖模型

對基于視圖的繪圖,對視圖的改變經(jīng)常會觸發(fā)調(diào)用視圖的drawRect:方法以重繪視圖內(nèi)容。但是此種方式的代價相對較高,因為它是CPU在主線程上的操作。Core Animation通過盡可能的使用圖形硬件操縱緩存后的位圖來避免了這種開銷,從而完成相同或相似的效果。

基于圖層的動畫

可在圖層上執(zhí)行的動畫類型:移動,縮放,旋轉(zhuǎn),透明度,圓角半徑,背景顏色


圖層對象定義了自己的幾何結(jié)構(gòu)


圖層使用兩種類型的坐標系統(tǒng)

圖層利用基于點的坐標系統(tǒng)單位坐標系統(tǒng)指定內(nèi)容的布局,當指定的值是直接映射到屏幕或相對于其他圖層的坐標,圖層的position屬性,則使用基于點的坐標系統(tǒng),與屏幕坐標不相關(guān)聯(lián),則使用單位坐標。比如圖層的anchorPoint屬性。

錨點是使用單位坐標系統(tǒng)的屬性之一。


錨點影響幾何結(jié)構(gòu)的操作

position屬性是相對于圖層的錨點被指定。并且任何你對圖層陰影的變換操作也是相對于錨點。

AnchorPoint相對于自身wh的百分比,0.0~1.0,position是相對于父視圖的坐標點。


圖層可在三維空間中操作

CALayer的transform屬性用來指定應(yīng)用到圖層和它內(nèi)嵌的子層上的變換。通常當你想更改圖層本身則使用該屬性。sublayerTransform屬性定義了僅應(yīng)用在子層上的變換以及給場景內(nèi)容添加透視效果。

如果是旋轉(zhuǎn),應(yīng)用一個旋轉(zhuǎn)角度的正弦和余弦值.


不同的圖層樹反映了不同的動畫狀態(tài)


使用Core Animation的app擁有三個圖層對象集合。每一個圖層對象集合在呈現(xiàn)app內(nèi)容上都扮演著不同的角色。

模型圖層樹

模型對象負責存儲所有動畫的目標值

呈現(xiàn)樹中的對象包含所有運行中的動畫的瞬時值

渲染樹中的對象執(zhí)行實際的動畫,并且對Core Animation是不公開的


你可能為了優(yōu)化app內(nèi)容的性能而選擇加入圖層對象而非視圖,原因在于圖層的開銷要比視圖低。

app主要與圖層樹中的對象進行交互,但可能有時會訪問呈現(xiàn)樹中的對象。具體地,訪問圖層樹中對象的presentationLayer屬性將返回一個在呈現(xiàn)樹中相對應(yīng)的對象。你可能會通過該對象獲取在動畫執(zhí)行過程中的某一時刻的屬性值。

重要:只在動畫運行時訪問呈現(xiàn)樹中的對象。當動畫在進行中,呈現(xiàn)樹就包含了圖層顯示在屏幕上的那一刻的值。該行為與圖層樹不同,圖層樹永遠只表示最終的目標值。


圖層與視圖的關(guān)系


圖層不是視圖的替代品。因此無法創(chuàng)建一個基于單一圖層對象的可視界面。圖層是視圖的基礎(chǔ)設(shè)施。具體地,圖層讓視圖的繪圖和動畫更簡單和高效,并且能在繪圖和動畫時保持高幀率。然而許多事情圖層無法做到。圖層不能處理事件、繪制內(nèi)容,特別是在響應(yīng)鏈中,或是做一些其他的事情。因此,每個app必須有一個或多個視圖來處理這類交互。

在iOS中,每一個視圖有一個相對應(yīng)的圖層對象。

比如說,如果你想使用相同的圖片在多個地方,你可以只加載圖片一次,然后將圖片和多個獨立的圖層對象相關(guān)聯(lián),最后添加這些圖層對象到圖層樹中。每一個圖層只會引用源圖片而不是嘗試在內(nèi)存中創(chuàng)建自身對圖片的拷貝。


構(gòu)建圖層對象


開啟對Core Animation的支持

iOS是自動支持圖層的


改變與視圖相關(guān)聯(lián)的圖層對象

改變視圖自有的圖層類

你可以通過覆蓋iOS視圖中的layerClass方法并返回一個需要的圖層類對象。默認是CALayer。以下情況需要自定義圖層類對象:

(1)視圖的繪圖內(nèi)容是由OpenGL ES實現(xiàn),此種情況你需要使用CAEAGLLayer對象。

(2)特殊的圖層讓你擁有更強的表現(xiàn)性能。

(3)需要利用某些特殊的Core Animation類,比如粒子發(fā)射器或者拷貝器。


不同的圖層擁有特定的行為

提供圖層的內(nèi)容

圖層是管理app內(nèi)容的數(shù)據(jù)對象。圖層的內(nèi)容由包含可視數(shù)據(jù)的位圖構(gòu)成。

(1)直接賦值一個UIImage對象給圖層對象contents屬性。(這個技術(shù)適用于圖層內(nèi)容從不或幾乎不改變的情形。)

(2)賦值一個代理給圖層,由代理負責繪制圖層內(nèi)容。(該技術(shù)適用于圖層內(nèi)容可能偶爾改變,且內(nèi)容可由外部對象提供,比如視圖。)

(3)定義一個CALayer的子類并覆蓋類的繪圖方法,有覆蓋的方法返回圖層的內(nèi)容。(該技術(shù)適用于你需要創(chuàng)建自定義圖層的子類,或者你想改變圖層基本的繪圖行為。)


使用圖片為圖層提供內(nèi)容

當賦值圖片時,記住提供的圖片的分辨率要與本地設(shè)備的分辨率相匹配。對于Retina顯示設(shè)備,這可能也需要你去調(diào)整圖片的contentsScale屬性。


使用代理提供圖層的內(nèi)容

圖層的內(nèi)容是動態(tài)改變的,調(diào)用delegate方法來填充:

(1)如果你的代理實現(xiàn)了displayLayer:方法,實現(xiàn)方法負責創(chuàng)建位圖并賦值給contents屬性。(CG需要自建上下文再繪制,UIKit直接繪制)

(2)如果你的代理實現(xiàn)的是drawLayer:inContext:方法,Core Animation創(chuàng)建一個位圖,創(chuàng)建一個用于繪制位圖的上下文,并調(diào)用代理方法填充該位圖。你的代理方法所要做的是將內(nèi)容畫在圖形上下文上。(CG拿上下文來繪制,UIKit要轉(zhuǎn)換上下文為當前上下文來繪制)

覆蓋displayLayer:方法在當你的app更傾向于載入或創(chuàng)建想要顯示的位圖的情況下適用。

如果你沒有預(yù)渲染的圖片或者輔助對象來創(chuàng)建位圖。代理對象可以使用drawLayer:inContext:方法動態(tài)的繪制內(nèi)容。

有圖層的視圖,是其代理,實現(xiàn)drawRect:


由子類提供圖層的內(nèi)容

如CATiledLayer類通過將大圖片拆成更小的可管理、可獨立渲染的碎片來管理大的圖片。因為只有圖層知道在某一時刻哪一個碎片需要被渲染,圖層會直接管理繪圖的行為。

子類化圖層類,你可使用下述的兩種方式繪制你的圖層內(nèi)容:

(1)覆蓋圖層的display方法并使用在方法中直接設(shè)置圖層的contents屬性。

(2)覆蓋圖層的drawInContext:方法并將需要的內(nèi)容繪制到提供的圖形上下文中。

用哪種方式取決于繪圖過程的控制力

display方法是更新圖層內(nèi)容的主要入口點,所以覆蓋這個方法讓你處于完全的過程控制中。覆蓋display方法也意味你需要負責contents屬性創(chuàng)建CGImageRef對象

如果你只是想繪制內(nèi)容(或讓你的圖層管理繪圖操作),你可以覆蓋drawInContext:方法并讓圖層為你創(chuàng)建內(nèi)容儲備。


調(diào)整提供的內(nèi)容

當給圖層的contents屬性賦值一個圖片,圖層的contentsGravity屬性確定圖片如何適合當前的邊界。使用contentsGravity屬性來確定你的內(nèi)容以最佳的呈現(xiàn)方式。

你可以向contentsGravity屬性賦予的值分為兩個分類:

(1)基于位置的引力約束允許你固定你的圖片到圖層矩形邊界的一個特殊的邊緣或角落,不會縮放圖片。-- Top,TopLeft/Right,Left,Right,Center,Bottom,BottomLeft/Right。

(2)基于縮放的引力約束允許你伸縮圖片使用多個選項之一,某些選項保留長寬比,有些則不保留。-- kCAGravityResizeAspect,kCAGravityResizeAspectFill,kCAGravityResize

圖層的contentsGravity屬性被設(shè)置為kCAGravityResize常量值,它是唯一一個不保留圖片的長寬比的選項。


使用高分辨率的圖片

圖層不知道當前設(shè)備的分辨率信息。圖層只是簡單的存儲一個指向位圖的指針,并用給定的有效像素以最佳的方式顯示。如果你賦值一個圖片給圖層的contents屬性,你必須給圖層的contentsScale屬性設(shè)置一個正確的值以告訴Core Animation關(guān)于圖片的分辨率。默認1.0,Retina-2.0。使用[[UIScreen mainScreen] scale]可獲取正確的縮放率。


調(diào)整圖層的可視樣式和外觀


圖層對象擁有內(nèi)建的可視裝飾,如邊框、背景色。你可以使用這些裝飾對圖層的主內(nèi)容進行補充。因為這些可視的裝飾不需要任何渲染。

圖層擁有自己的背景和邊框

背景被渲染在圖層的內(nèi)容圖片的后方,邊框被渲染在內(nèi)容圖片的前方。

注意使用模式圖片時,渲染是由Core Graphics完成,它使用的是標準坐標系統(tǒng)。渲染結(jié)果是顛倒的??梢允褂?b>[backgroundLayer setTransform:CATransform3DMakeScale(1.0, -1.0, 1.0)];

opaque == YES,提升性能。給圖層設(shè)置了非零的圓角半徑,則不可以將圖層標記為不透明類型。



圖層支持圓角半徑? --? cornerRadius

圓角半徑不影響圖層的contents屬性中得圖片,除非masksToBounds屬性被設(shè)置為YES。


圖層內(nèi)建支持陰影

CALayer類包括若干個配置陰影的屬性。使用圖層你可以控制陰影的顏色,相對于圖層內(nèi)容的位置(shadowOffset)透明度(shadowOpacity)以及形狀。

如果你啟用了圖層的masksToBounds屬性,圍繞邊緣的陰影將被裁減掉。如果既想要陰影又要啟用maskToBounds為YES,那么你可以使用兩個圖層。第一個是包含內(nèi)容的圖層,將該圖層的maskToBounds屬性設(shè)置為YES,然后創(chuàng)建一個相同尺寸且含有陰影效果的第二個圖層,最后調(diào)用第二個圖層的addSublayer方法將第一個圖層嵌入到第二個圖層中就可以了。

注意:iOS平臺上不能給圖層添加濾鏡


給圖層添加自定義屬性

CAAnimation和CALayer類擴展了鍵值編碼--KVC以對自定義屬性進行支持。你可以使用該行為給圖層添加數(shù)據(jù)并使用你定義的鍵檢索對應(yīng)的值。你甚至可以給你的自定義屬性關(guān)聯(lián)動作,當該屬性的值發(fā)生變化,對應(yīng)的動畫將會被執(zhí)行。


圖層的內(nèi)容動畫


改變圖層框架矩形的尺寸,改變其在屏幕上的位置,應(yīng)用旋轉(zhuǎn)變換,改變它的透明度。

用簡單的動畫表現(xiàn)圖層屬性的變化? --? CABasicAnimation


你可以以顯式或隱式的執(zhí)行簡單的動畫。隱式動畫使用默認的定時器動畫屬性展現(xiàn)動畫。而顯式動畫需要你為動畫對象配置一些參數(shù)。所以當默認的定時器能夠很好的為你服務(wù)并且你所要的動畫效果不需要太多代碼時,隱式動畫則非常的適合你。

為了觸發(fā)隱式動畫,你所要做的是更新圖層對象的屬性。

為了顯式地使用動畫對象呈現(xiàn)相同的變化,創(chuàng)建一個CABasicAnimation對象并配置該對象的動畫參數(shù)。為了執(zhí)行一個動畫,你使用addAnimation:forKey:方法將動畫對象添加到你想要展現(xiàn)動畫的圖層上。

不同于隱式動畫,隱式動畫會更新圖層對象的值(就是直接賦值)。而顯示動畫不會更改圖層樹中的數(shù)據(jù)。顯示動畫僅是創(chuàng)建了一個動畫。要手動改變值。


用關(guān)鍵幀動畫表現(xiàn)圖層屬性的變化? --? CAKeyfarmeAnimation


顯示了一個圖層position屬性的5秒動畫。position是動畫跟隨一個路徑。使用一個CGPathRef數(shù)據(jù)類型指定的。-- ?其實就是原來用CG畫圖的,現(xiàn)在把過程改成動畫。

指定關(guān)鍵幀的值

指定關(guān)鍵幀值的主要方式以對象數(shù)組作為它的值。但是對于包含CGPoint數(shù)據(jù)類型(比如圖層的anchorPoint屬性和position屬性),你可以指定一個CGPathRef數(shù)據(jù)類型替代。

關(guān)鍵幀值數(shù)組 -> 然而一些對象必須在添加到數(shù)組中之前被轉(zhuǎn)換為id類型,所有標量類型或結(jié)構(gòu)體必須被包裝為對象,比如:

(1)對于屬性類型為CGRect(例如bounds和frame屬性),使用NSValue對象包裝每一個矩形。

(2)對于圖層的變換屬性,使用NSValue包裝每一個CATransform3D矩陣。動畫這個屬性將引起關(guān)鍵幀動畫給圖層輪流應(yīng)用每個變換矩陣。

(3)對于borderColor屬性,在添加到數(shù)組之前,轉(zhuǎn)換CGColorRef數(shù)據(jù)類型為id類型。

(4)對于屬性為CGFloat類型,在添加到數(shù)組之前,使用NSNumber包裝每個值。

(5)為了動畫圖層的內(nèi)容屬性,指定一個CGImageRef數(shù)據(jù)類型屬性。

對于一個CGPoint數(shù)據(jù)類型的屬性,你可以創(chuàng)建一個點(使用NSValue對象包裝)數(shù)組,OR 使用CGPathRef對象指定跟蹤的路徑。<1> 當你指定一個點數(shù)組,關(guān)鍵幀動畫對象在每一個連續(xù)的點之間繪制一條線,并沿著這些線移動。<2> 當你指定一個CGPathRef對象,動畫起始于路徑的開始點并跟隨路徑線移動,這包括沿著任何曲面。你可以使用開放的或者封閉的路徑。

有沒有的框架可以簡化這種封裝?????


指定關(guān)鍵幀動畫的定時器

關(guān)鍵幀動畫的定時與步調(diào)比基本動畫來的要復(fù)雜。以下是幾個用于控制定時和步調(diào)的屬性:

calculationMode屬性定義了計算動畫定時的算法。該屬性值會影響其他與定時相關(guān)屬性的使用方式。

(1)線性和曲線動畫,動畫的calculationMode屬性被設(shè)置為kCAAnimationLinearCAAnimationCubic,屬性值被用于提供定時器信息以生成動畫。這些模式值讓你最大化控制動畫的定時器。

(2)節(jié)奏動畫,動畫的calculationMode屬性被設(shè)置為kCAAnimationPacedkCAAnimationCubicPaced,這些屬性值不依賴由keyTimes或timingFunctions屬性提供的額外定時器值。相反,定時器值被隱式地計算以提供一個常速率動畫。

(3)離散動畫,動畫的calculationMode屬性被設(shè)置為kCAAnimationDiscrete,該值將引起動畫屬性從一個關(guān)鍵幀跳到另一個沒有任何補間動畫的下一個關(guān)鍵幀。計算模式使用keyTimes屬性值,但忽略timingFunctions屬性。

(4)keyTimes屬性為應(yīng)用在每一關(guān)鍵幀指定應(yīng)用到每一個關(guān)鍵幀上的計時器。該屬性只在calculationMode屬性被設(shè)置為kCAAnimationLinear,kCAAnimaitonDiscrete,kCAAnimationCubic時被使用。它不使用在節(jié)奏動畫中。

(5)timingFunctions屬性指定使用在每一個關(guān)鍵幀部分的定時曲線(該屬性替換了繼承的timingFunction屬性)。

如果你想自己處理動畫的定時,可以使用kCAAnimationLinear或kCAAnimaitonCubic模式與keyTimes和timingFunctions屬性。keyTimes定義了應(yīng)用在每一關(guān)鍵幀的時間點。所有中間值的定時由定時函數(shù)控制,定時函數(shù)允許你對各個部分應(yīng)用緩入或緩出曲線定時。如果你不指定任何定時函數(shù),動畫將會是線性的。


停止一個隱式動畫的運行


提前停止動畫:

(1)為了從圖層上移除單獨的動畫對象,調(diào)用圖層的removeAnimationForKey:方法移除你的動畫對象。該方法使用的鍵要與調(diào)用addAnimation:forKey:方法傳入的鍵一致。你指定的鍵必須不為nil。

(2)為了移除圖層的所有動畫對象。調(diào)用圖層的removeAllAnimations方法。該方法立即會移除所有進行中的動畫,并使用圖層當前的狀態(tài)信息重繪圖層。

外觀突然的跳躍 -- 呈現(xiàn)樹中的對象的最終值...More


同時動畫多個屬性變化? --? CAAnimationGroup

有點像dispatch_group。更高級的可以用一個事物對象。


檢測一個動畫的結(jié)束 ?-- ?block 和 delegate

Core Animaiton提供對動畫開始與結(jié)束的檢測支持。比如說你可能使用開始通知設(shè)置一些相關(guān)狀態(tài)信息,使用對應(yīng)的結(jié)束通知清理這些狀態(tài)。

(1)使用setCompletionBlock:方法添加一個完成block給當前的事務(wù)。當事務(wù)中的所有動畫完成后,事務(wù)將執(zhí)行你的完成塊。

(2)給CAAnimaiton對象賦值一個代理,該代理實現(xiàn)了animationDidStart:方法和animaitonDidStop:finished:代理方法。

兩個動畫鏈接在一起使用,動畫對象的beginTime屬性在希望的時間啟動動畫。為了將兩個動畫鏈接在一起,設(shè)置第二個動畫的開始時間為第一個動畫的結(jié)束時間。


如何動畫有圖層支持視圖


iOS中圖層更改的規(guī)則

[UIView? animateWithDuration:1.0? animations:^{}];

記住將更新視圖約束作為動畫的一部分


構(gòu)建圖層層級


將圖層排列為圖層層級

添加、插入、移除子圖層

addSublayer:

insertSublayer:above:? --? insertSublayer:atIndex:? --? insertSublayer:below:圖層的可視性主要由它的zPosition屬性決定,然后是由其在子圖層數(shù)組中的位置決定。

removeFromSuperlayer

replaceSublayer:with

子圖層的位置與尺寸

bounds && position

圖層層級對動畫的影響

speed動畫運行速度。


調(diào)整你的圖層層次的布局

如果你的app的圖層都是與視圖相關(guān),使用基于圖層的布局支持對你的視圖尺寸與位置的更新,以應(yīng)對尺寸與位置的變化。


手動規(guī)劃你的圖層層次

你可以通過在父圖層的代理對象上實現(xiàn)layoutSublayersOfLayer:方法手動處理布局。

實現(xiàn)一個自定義圖層子類,你的子類可以覆蓋layoutSublayers方法并使用該方法(而不是代理)去處理任何布局任務(wù)。子圖層的定位進行完全的控制的情況下,你只需要覆蓋這個方法。


子圖層與裁剪


與視圖不同的,一個父圖層不會自動地裁剪超出其邊界的子圖層的內(nèi)容。默認情況下,父圖層允許他的子圖層完全的被顯示。通過設(shè)置圖層的masksToBounds屬性為YES,你可以重新啟用裁減功能。

masksToBounds ?-- ?裁剪蒙版含義


在圖層之間轉(zhuǎn)換坐標值

某圖層中的一個坐標值轉(zhuǎn)換為屏幕坐標位置相同而處在不同圖層的一個坐標值。CALayer提供了一組簡單的轉(zhuǎn)換方法以應(yīng)對這種情況:

(1)convertPoint:fromLayer:

(2)convertPoint:toLayer:

(3)convertRect:fromLayer:

(4)convertRect:toLayer:

在兩個圖層之間轉(zhuǎn)換時間,使用convertTime:fromLayer:與convertTime:toLayer:方法。


高級動畫技巧


過渡動畫支持改變圖層的可視性

一個過渡動畫對象為圖層創(chuàng)建一個可動畫的可視過渡。與基于屬性的動畫不同,一個過渡動畫操縱一個圖層的緩存圖片以創(chuàng)建可視效果,如果通過單獨的改變屬性實現(xiàn)會非常的困難,也許根本無法實現(xiàn)。標準的過渡類型包括:將舊視圖移開顯示新視圖、推入、移動、淡入淡出動畫。

為了實現(xiàn)一個一個過渡動畫,創(chuàng)建一個CATransition對象,然后添加該對象到包含過渡特效的圖層上。你使用過渡對象指定所要執(zhí)行的過渡類型以及過渡動畫的開始點和結(jié)束點


自定義動畫的定時

時間系統(tǒng)是動畫的一個重要部分。通過Core Animation方法和CAMediaTiming協(xié)議可為動畫指定精確的時間信息。共有兩個Core Animation類適配該協(xié)議。其中之一是CAAnimation類,所以你可以在動畫對象中指定時間信息。其二是CALayer,你可以為隱式動畫配置一些與時間相關(guān)的功能。

為了幫助你確定一個圖層的適當時間值,CALayer類定義了convertTime:fromLayer:以及convertTime:toLayer:方法。

CFTimeInterval ?localLayerTime = [myLayer ?convertTime:CACurrentMediaTime() fromLayer:nil];

(1) 使用beginTime屬性設(shè)置動畫的開始時間。如果你延時了動畫的開始。你可能也想設(shè)置fillMode屬性為kCAFillModeBackwards。

(2) autoreverses屬性引起一個動畫在指定的持續(xù)時間內(nèi)執(zhí)行并返回到動畫的開始值。你可以將此屬性與repeatCount屬性聯(lián)合使用,讓動畫在開始與結(jié)束值之間反復(fù)來回。

對動畫組中的動畫使用timeOffset屬性,讓動畫一開始就出現(xiàn)在以后某時刻才會出現(xiàn)的狀態(tài)。其實就是偏移。


暫停與恢復(fù)動畫

為了暫停一個動畫,你可以利用圖層適配CAMediaTiming協(xié)議這一點,設(shè)置圖層動畫的速度為0.0。非0就開始動畫。


顯式事務(wù)可以改變動畫的參數(shù)

對圖層屬性的每次更改都是事務(wù)的一部分。CATransaction類管理動畫的創(chuàng)建和分組并在適當?shù)臅r間執(zhí)行動畫??梢詣?chuàng)建顯式事務(wù)以能夠更精確的管理動畫。

使用CATransaction類提供的方法創(chuàng)建與管理事務(wù)。通過調(diào)用begin類方法,可以開始(或隱式地創(chuàng)建)一個新的事務(wù);調(diào)用commit類方法可結(jié)束一個事務(wù)。

kCATransactionAnimationDuration

[CATransaction begin];

[CATransaction setValue:[NSNumber numberWithFloat:10.0f];

forKey:kCATransactionAnimationDuration];

[CATransaction commit];


給動畫添加透視

當更改一個場景的透視,你需要更改被觀察圖層的父圖層subLayerTransform矩陣。


改變一個圖層的默認行為

Core Animation使用動作對象為圖層實現(xiàn)了隱式動畫行為。動作對象服從CAAction協(xié)議并定義了一些運行于圖層的相關(guān)行為。所有CAAnimation對象都實現(xiàn)了這個協(xié)議。


自定義適配CAAction協(xié)議的動作對象

適配CAAction協(xié)議并實現(xiàn)runActionForKey:object:arguments:方法。在該方法中利用可用的信息執(zhí)行任何你想要在圖層上的動作。

當你定義了一個動作對象,你必須決定動作以何種方式被觸發(fā)。動作的觸發(fā)器定義了你用于注冊動作的鍵。下面被觸發(fā):

(1)圖層的某一個屬性值被改變。識別動作的鍵是屬性名。

(2)圖層變成可視或被加入到圖層層次中。則識別動作的鍵為kCAOnOrderIn。

(3)圖層從圖層層次中被移除。則識別動作的鍵為kCAOnOrderOut。

(4)圖層是即將包含一個變換動畫。則識別動作的鍵為kCATransition。


動作對象設(shè)置給圖層才產(chǎn)生效果

當一個適當?shù)氖录l(fā)生在圖層上,圖層調(diào)用它的actionForKey:方法搜索與鍵關(guān)聯(lián)的動作對象。

Core Animation以下面的順序搜索動作對象:

(1)如果圖層有一個代理,并且代理實現(xiàn)了actionForLayer:forKey:方法,圖層調(diào)用該方法。代理必須完成下面所述操作之一:

<1> 返回給定的鍵指定的動作對象

<2> 如果代理不處理動作則返回nil,而搜索操作將繼續(xù)。

<3> 返回NSNull對象,這將引起搜索操作立即結(jié)束。

(2)圖層在圖層的action字典內(nèi)搜索給定的鍵

(3)圖層在style字典中查詢一個包含鍵的動作字典。(換句話說,style字典包含一個actions鍵,它的值也是字典。圖層在第二個字典中搜索給定的鍵。)

(4)圖層調(diào)用它的defaultActionForKey:類方法。

(5)圖層執(zhí)行由Core Animation定義的隱式動作(如果有)。

當它找到了一個動作對象,圖層調(diào)用對象的runActionForKey:object:arguments:方法執(zhí)行動作。


設(shè)置 動作對象的位置 依賴于你打算 如何更改圖層。

(1)對于只應(yīng)用在指定環(huán)境的動作,或?qū)τ谝呀?jīng)使用代理對象的圖層,提供一個代理和實現(xiàn)它的actionForLayer:forKey:方法。

(2)對于不使用代理的圖層對象,添加動作到圖層的actions字典。

(3)與定義在圖層對象上的自定義屬性相關(guān)的動作,包括動作在圖層的style字典。

(4)對于那些是圖層行為基礎(chǔ)的動作,子類化圖層并覆蓋defaultActionForKey:方法。


使用CATransaction類臨時禁用動作

通過創(chuàng)建一個顯示事務(wù)并設(shè)置它的kCATransactionDisableActions屬性為True禁用隱式動畫。


提升動畫的性能

Core Animation是提升based-app動畫幀率的最佳方式 ,但使用Core Animation并不保證性能一定會得到提升。

常規(guī)的技巧和竅門


盡可能使用不透明圖層

設(shè)置opaque = YES可以讓CA知道不需要給圖層維持alpha通道,沒有alpha通道意味著就不需要渲染這層的背景內(nèi)容了,從而節(jié)省了渲染時間。然后這個屬性主要是用于設(shè)置或者以層為基礎(chǔ)的視圖的,也或者是用于核心動畫創(chuàng)造的底層bitmap層的情況。如果把一張圖像直接設(shè)置為層的contents屬性,那么這個圖像的alpha通道會被強制保留,無論你設(shè)不設(shè)定這個值。


將復(fù)雜路徑拆分成簡單路徑

CAShapeLayer類根據(jù)你提供的路徑來渲染到bitmap圖像,在合成的時候渲染成內(nèi)容。這么做的優(yōu)點是層總是在最佳分辨率繪制路徑,但是這個優(yōu)點會消耗額外的渲染時間。如果這個路徑太復(fù)雜,渲染的代價就會很高,并且如果這個路徑的尺寸經(jīng)常改變(這會導(dǎo)致重繪也經(jīng)常發(fā)生),用于繪畫的時間也會增加,這會成為一個阻止最佳表現(xiàn)性能的瓶頸

有一個辦法去降低繪制形狀層的時間,就是把復(fù)雜的形狀分拆成簡單的形狀。用更簡單的路徑和多層用于CAShapeLayer對象,這比繪制一個大的復(fù)雜路徑時間快得多。因為繪制操作發(fā)生在CPU,合成工作發(fā)生在GPU,當然這種優(yōu)化也取決于你的內(nèi)容。因此,優(yōu)化前以現(xiàn)有效果為基準很重要。


顯式為相同的圖層設(shè)置contents屬性 ?-- ?圖層會緩存

如果你在多個層對象上使用同一張圖片,自己加載圖像,把這個圖像直接分派給這些層對象的contents屬性。分配一個圖像到contents屬性可以預(yù)防分配用于內(nèi)容儲備的內(nèi)存空間(UIView實際并不將自己繪制到屏幕上,而是先繪制到它的圖層上,然后是圖層顯示在屏幕上,視圖并不會頻繁的重繪;相反,它的繪圖結(jié)果會被緩存起來,而繪圖的緩存版本(后備存儲)將被用到適當?shù)牡胤剑?。反而這個層用你提供的圖像當做后備存儲。當幾個層用同樣的圖片,那么這些層就在共享一份內(nèi)存而不是為自己再分配一個圖片拷貝。

UIView -> 圖層 -> 屏幕上


總是將圖層的尺寸設(shè)置為整數(shù)值

如果需要,可以使用異步的方式渲染圖層

任何在代理方法drawLayer:inContext或視圖的drawRect:方法中的繪制操作都默認是和主線程是同步的,在某種情況下,同步的繪制你的內(nèi)容可能不會有最好的效果和表現(xiàn)。如果注意到動畫執(zhí)行的不好,可能就得試試drawsAsynchronously這個層的屬性(iOS 6引入),讓這些操作在后臺線程中工作。如果你這么做了,得確定繪制代碼是線程安全的,而且理所應(yīng)當你應(yīng)該在將異步繪圖的代碼置入你的產(chǎn)品代碼之前總是測試異步繪圖的性能。


當給圖層添加一個陰影指定一個陰影路徑

讓Core Animation自己決定陰影的形狀是個大的開銷且影響app的表現(xiàn)。相比讓它自己決定,應(yīng)該用shadowPath屬性明確地指定一個陰影形狀。當你這么干的時候,核心動畫用這個形狀去繪制和緩存陰影特效。對那些從不改變或者很少改變形狀的層,這是一個很好的效果提升通過減少渲染數(shù)量。


圖層樣式屬性動畫


幾何屬性

bounds

position

frame(根據(jù)bounds和position計算得出,該屬性不是一個可動畫屬性)

anchorPoint

cornerRadius

transform

zPosition


背景屬性

Core Animation首先會渲染圖層的背景。

backgroundColor


圖層內(nèi)容

如果圖層有任何的內(nèi)容,該內(nèi)容將被渲染在背景顏色的上面。你可以通過<1>直接設(shè)置一副位圖提供圖層內(nèi)容,或使用<2>一個代理指定內(nèi)容,或是<3>子類化圖層并直接繪制內(nèi)容。

帶有圓角半徑的圖層不會自動裁剪它們的內(nèi)容;然而,設(shè)置圖層的masksToBounds = YES將引起圖層裁減掉圓角以外的內(nèi)容

contents

contentsGravity

masksToBounds


子圖層的內(nèi)容

sublayers

lmasksToBounds

lsublayerTransform


邊框?qū)傩?/b>

borderColor

lborderWidth


濾鏡屬性? --? 在iOS中,圖層忽略任何你賦值給他的濾鏡值

陰影屬性

可以配置陰影的形狀、透明度、偏移、模糊半徑。

hadowColor

lshadowOffset

lshadowOpacity

lshadowRadius

lshaodwPath


不透明度屬性? --? opacity


蒙版屬性? --? mask

你可以使用一個蒙版遮蔽所有或部分圖層內(nèi)容。蒙版本身是一個圖層對象,它的alpha通道被用于決定被遮蔽的內(nèi)容和被透射的內(nèi)容。


可動畫屬性

CALayer可動畫屬性


鍵值編碼擴展

Core Animation擴展了NSKeyValueCoding協(xié)議,因為它與CAAnimation、CALayer有關(guān)。擴展包括為一些鍵添加了默認的值、擴展了包裝轉(zhuǎn)換,并加入了對CGPoint、CGRect、CGSize和CATransform3D類型的鍵路徑支持。


鍵值編碼適應(yīng)的容器類

CAAnimation和CALayer是鍵值編碼適應(yīng)的容器類


支持的默認值

依靠一個類為沒有設(shè)置值的鍵提供一個默認值,Core Animation為鍵值編碼加入了一層轉(zhuǎn)換操作。CAAnimation和CALayer類支持這層轉(zhuǎn)換,你可以使用defaultValueForKey:類方法。

包裝轉(zhuǎn)換

當鍵的值的數(shù)據(jù)類型是一個標量或C語言的結(jié)構(gòu)體,你必須在將值賦值到圖層之前將值包裝成對象。

CGPoint,CGSize,CGRect,CGTransform3D -> NSValue


鍵路徑對結(jié)構(gòu)體的支持


CAAnimation和CALayer類可以使用鍵路徑(KeyPath)訪問已選擇的結(jié)構(gòu)體域。

CATransform3D鍵路徑

transform.rotation.z的鍵路徑。

rotation + scale + translation.x.y.z

[myLayer setValue:[NSNumber numberWithFloat:10.0] forKeyPath:@”transform.translation.x”];


CGPoint鍵路徑? --? position.x.y

CGSize鍵路徑 ?-- ?.width.height

CGRect鍵路徑? --? bounds.size.width

orign.x.y,size.width.height

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

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

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