UIView是iOS系統(tǒng)中界面元素的基礎(chǔ), 所有的界面元素都繼承自它, UIView本身完全是由CoreAnimation來實(shí)現(xiàn). 真正的繪圖部分, 是由一個(gè)CALayer類來管理. UIView更像是一個(gè)CALayer的管理器, 所以訪問它的與繪圖和坐標(biāo)相關(guān)的屬性, 如frame, bounds等, 實(shí)際上都是在訪問其所包含的CALayer的相關(guān)屬性. 因此, 可以在所有UIView的子類上實(shí)現(xiàn)動(dòng)畫效果.
UIView繼承自UIResponder, 能接收并響應(yīng)事件, 負(fù)責(zé)顯示內(nèi)容的管理, 而CALayer繼承自NSObject, 不能響應(yīng)事件, 負(fù)責(zé)顯示內(nèi)容的繪制.
UIView可以響應(yīng)事件,Layer不可以
UIKit使用UIResponder作為響應(yīng)對(duì)象,來響應(yīng)系統(tǒng)傳遞過來的事件并進(jìn)行處理。UIApplication、UIViewController、UIView、和所有從UIView派生出來的UIKit類(包括UIWindow)都直接或間接地繼承自UIResponder類。
在 UIResponder中定義了處理各種事件和事件傳遞的接口, 而 CALayer直接繼承 NSObject,并沒有相應(yīng)的處理事件的接口。
UIView主要是對(duì)顯示內(nèi)容的管理而 CALayer 主要側(cè)重顯示內(nèi)容的繪制
UIView主要是對(duì)顯示內(nèi)容的管理, 而CALayer主要是顯示內(nèi)容的繪制. UIView是CALayer的CALayerDelegate, 在代理方法內(nèi)部[UIView(CALayerDelegate) drawLayer:inContext]調(diào)用UIView的drawRect方法, 從而繪制出UIView的內(nèi)容. UIView的顯示內(nèi)容由內(nèi)部的CALayer:display方法來實(shí)現(xiàn).
編程問題都可以抽離出機(jī)制和策略部分。機(jī)制一旦實(shí)現(xiàn),就會(huì)很少更改,但策略會(huì)經(jīng)常得到優(yōu)化。CALayer也可以看做是一種機(jī)制,提供圖層繪制,CALayer的頭文件基本上是沒怎么變過的,而UIView可以看做是策略,變動(dòng)很多。越是底層越是機(jī)制,越是機(jī)制就越是穩(wěn)定。機(jī)制與策略分離,可以使得需要修改的代碼更少,特別是底層代碼,這樣可以提高系統(tǒng)的穩(wěn)定性。UIView遮蔽了大部分的CALayer接口,抽取構(gòu)造出更易用的frame和動(dòng)畫實(shí)現(xiàn),這樣上手更容易。
frame, position, bounds調(diào)用
一個(gè)CALayer的frame是由其anchorPoint, position, bounds, transform共同決定的, 而一個(gè)UIView的的frame只是簡(jiǎn)單地返回CALayer的frame, 同樣UIView的center和bounds也只是簡(jiǎn)單返回CALayer的Position和Bounds對(duì)應(yīng)屬性
在做 iOS 動(dòng)畫的時(shí)候,修改非 RootLayer的屬性(譬如位置、背景色等)會(huì)默認(rèn)產(chǎn)生隱式動(dòng)畫,而修改UIView則不會(huì)
對(duì)于每一個(gè) UIView 都有一個(gè) layer,把這個(gè) layer 且稱作RootLayer,而不是 View 的根 Layer的叫做 非 RootLayer。我們對(duì)UIView的屬性修改時(shí)時(shí)不會(huì)產(chǎn)生默認(rèn)動(dòng)畫,而對(duì)單獨(dú) layer屬性直接修改會(huì),這個(gè)默認(rèn)動(dòng)畫的時(shí)間缺省值是0.25s.
在 Core Animation 編程指南的 “How to Animate Layer-Backed Views” 中,對(duì)為什么會(huì)這樣做出了一個(gè)解釋:
UIView 默認(rèn)情況下禁止了 layer 動(dòng)畫,但是在 animation block 中又重新啟用了它們
是因?yàn)槿魏慰蓜?dòng)畫的 layer 屬性改變時(shí),layer 都會(huì)尋找并運(yùn)行合適的 'action' 來實(shí)行這個(gè)改變。在 Core Animation 的專業(yè)術(shù)語中就把這樣的動(dòng)畫統(tǒng)稱為動(dòng)作 (action,或者 CAAction)。
layer 通過向它的 delegate 發(fā)送 actionForLayer:forKey: 消息來詢問提供一個(gè)對(duì)應(yīng)屬性變化的 action。delegate 可以通過返回以下三者之一來進(jìn)行響應(yīng):
- 它可以返回一個(gè)動(dòng)作對(duì)象,這種情況下 layer 將使用這個(gè)動(dòng)作。
- 它可以返回一個(gè) nil, 這樣 layer 就會(huì)到其他地方繼續(xù)尋找。
- 它可以返回一個(gè) NSNull 對(duì)象,告訴 layer 這里不需要執(zhí)行一個(gè)動(dòng)作,搜索也會(huì)就此停止。
當(dāng) layer 在背后支持一個(gè) view 的時(shí)候,view 就是它的 delegate;
CALayer中的隱式動(dòng)畫
每一個(gè)UIView內(nèi)部都默認(rèn)關(guān)聯(lián)著一個(gè)CALayer,我們可用稱這個(gè)Layer為Root Layer(根層)
所有的非Root Layer,也就是手動(dòng)創(chuàng)建的CALayer對(duì)象,都存在著隱式動(dòng)畫
當(dāng)對(duì)非Root Layer的部分屬性進(jìn)行修改時(shí),默認(rèn)會(huì)自動(dòng)產(chǎn)生一些動(dòng)畫效果,而這些屬性稱為Animatable Properties(可動(dòng)畫屬性)
當(dāng)遇到給某個(gè)控件添加CALayer層并讓控件擁有動(dòng)畫效果時(shí),CALayer與控件不同步,則需要關(guān)閉隱式動(dòng)畫
[CATransaction begin];
// 關(guān)閉隱式動(dòng)畫
[CATransaction setDisableActions:YES];
view.layer.position = CGPointMake(10, 10);
[CATransaction commit];
為什么CALayer不能直接使用UIColor,UIImage
layer.backgroundColor = [UIColor redColor].CGColor;
首先,CALayer是定義在QuartzCore框架中的,CGImageRef、CGColorRef兩種數(shù)據(jù)類型是定義在CoreGraphics框架中的
,而UIColor和UIImage是定義在UIKit框架中的。
其次,QuartzCore框架和CoreGraphics框架是可以跨平臺(tái)使用的,在iOS和Mac OS X上都能使用
但是UIKit只能在iOS中使用。
所以,為了保證可移植性,QuartzCore不能使用UIImage、UIColor,只能使用CGImageRef、CGColorRef。