在 iOS 中,所有的 view 都是由一個(gè)底層的 layer 來(lái)驅(qū)動(dòng)的绊汹。view 和它的 layer 之間有著緊密的聯(lián)系,view 其實(shí)直接從 layer 對(duì)象中獲取了絕大多數(shù)它所需要的數(shù)據(jù)扮宠。layer側(cè)重于圖形的顯示西乖,而view相當(dāng)于layer的管理者。CALayer屬于QuartzCore框架,用于在iOS和Mac OS系統(tǒng)上可見(jiàn)元素的繪制,和屬于UIKit框架的UIView的關(guān)系是,UIView默認(rèn)會(huì)創(chuàng)建一個(gè)CALayer屬性,用于圖象的繪制和顯示.CALayer也可以單獨(dú)創(chuàng)建坛增。
1.首先UIView可以響應(yīng)事件获雕,Layer不可以.
UIKit使用UIResponder作為響應(yīng)對(duì)象,來(lái)響應(yīng)系統(tǒng)傳遞過(guò)來(lái)的事件并進(jìn)行處理收捣。UIApplication届案、UIViewController、UIView罢艾、和所有從UIView派生出來(lái)的UIKit類(lèi)(包括UIWindow)都直接或間接地繼承自UIResponder類(lèi)楣颠。
在 UIResponder中定義了處理各種事件和事件傳遞的接口, 而 CALayer直接繼承 NSObject,并沒(méi)有相應(yīng)的處理事件的接口咐蚯。
2.View和CALayer的Frame映射及View如何創(chuàng)建CALayer.
一個(gè) Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform(圖層旋轉(zhuǎn)) 共同決定的
布局
要分析CALayer的anchorPoint和position屬性,首先要討論一下CALayer的布局.
我們所熟悉的UIView有三個(gè)重要的布局屬性:frame,bounds和center,CALayer對(duì)應(yīng)的叫做frame,bounds和position.
frame:代表了圖層的外部坐標(biāo)(在父圖層上占據(jù)的空間)
bounds:為內(nèi)部坐標(biāo)
position:代表了相對(duì)父圖層anchorPoint的位置
錨點(diǎn)
如何理解anchorPoint(錨點(diǎn))?
和position共同決定圖層相對(duì)父圖層的位置,即frame的x,y
在圖層旋轉(zhuǎn)時(shí)的固定點(diǎn)
錨點(diǎn)使用單位坐標(biāo)來(lái)描述,范圍為左上角{0, 0}到右下角{1, 1},默認(rèn)坐標(biāo)是{0.5, 0.5}.
錨點(diǎn)和position的關(guān)系
position是圖層的anchorPoint在父圖層中的位置坐標(biāo).
anchorPoint和position共同決定圖層相對(duì)父圖層的位置,即frame屬性的frame.origin.
單方面修改anchorPoint或者position并不會(huì)對(duì)彼此產(chǎn)生影響,修改其中一個(gè)值,受影響的只會(huì)是frame.origin.
圖層旋轉(zhuǎn)時(shí),如何修改錨點(diǎn)
在圖層旋轉(zhuǎn)時(shí),錨點(diǎn)就是圖層的固定點(diǎn),旋轉(zhuǎn)是沿著這個(gè)定點(diǎn)進(jìn)行的.(表盤(pán)布局demo)
單方面修改anchorPoint或者position并不會(huì)對(duì)彼此產(chǎn)生影響,修改其中一個(gè)值,受影響的只會(huì)是frame.origin.
anchorPoint和position共同決定了frame
frame.origin.x = position.x - anchorPoint.x * bounds.size.width童漩;
frame.origin.y = position.y - anchorPoint.y * bounds.size.height
anchorPoint是圖層在旋轉(zhuǎn)時(shí)的固定點(diǎn)
一個(gè) View 的 frame 只是簡(jiǎn)單的返回 Layer的 frame,View 的 Center 和 Bounds 只是直接返回layer 對(duì)應(yīng)的 Position 和 Bounds.
[UIView?_createLayerWithFrame]
[Layer?setBounds:bounds]
[UIView?setFrame:Frame]
[Layer?setFrame:frame]
[Layer?setPosition:position]
[Layer?setBounds:bounds]
View中frame getter方法春锋,bounds和center矫膨,UIView并沒(méi)有做什么工作;它只是簡(jiǎn)單的各自調(diào)用它底層的CALayer的frame期奔,bounds和position方法侧馅。
3.UIView主要是對(duì)顯示內(nèi)容的管理而 CALayer 主要側(cè)重顯示內(nèi)容的繪制。
分別重寫(xiě)UIView 和 CALayer?父類(lèi)的方法:
[UIView?drawRect:rect]//UIView????
[CALayer?display]//CALayer
UIView 是 CALayer 的CALayerDelegate呐萌,在代理方法內(nèi)部[UIView(CALayerDelegate) drawLayer:inContext]調(diào)用 UIView 的 DrawRect方法馁痴,從而繪制出了 UIView 的內(nèi)容。
4.在做 iOS 動(dòng)畫(huà)的時(shí)候搁胆,修改非 RootLayer的屬性(譬如位置弥搞、背景色等)會(huì)默認(rèn)產(chǎn)生隱式動(dòng)畫(huà),而修改UIView則不會(huì)渠旁。
對(duì)于每一個(gè) UIView 都有一個(gè) layer,把這個(gè) layer 且稱作RootLayer,而不是 View 的根 Layer的叫做 非 RootLayer攀例。我們對(duì)UIView的屬性修改時(shí)時(shí)不會(huì)產(chǎn)生默認(rèn)動(dòng)畫(huà),而對(duì)單獨(dú) layer屬性直接修改會(huì)顾腊,這個(gè)默認(rèn)動(dòng)畫(huà)的時(shí)間缺省值是0.25s.
在 Core Animation 編程指南的 “How to Animate Layer-Backed Views” 中粤铭,對(duì)為什么會(huì)這樣做出了一個(gè)解釋?zhuān)?/p>
UIView 默認(rèn)情況下禁止了 layer 動(dòng)畫(huà),但是在 animation block 中又重新啟用了它們
是因?yàn)槿魏慰蓜?dòng)畫(huà)的 layer 屬性改變時(shí)杂靶,layer 都會(huì)尋找并運(yùn)行合適的 'action' 來(lái)實(shí)行這個(gè)改變梆惯。在 Core Animation 的專(zhuān)業(yè)術(shù)語(yǔ)中就把這樣的動(dòng)畫(huà)統(tǒng)稱為動(dòng)作 (action酱鸭,或者 CAAction)。
layer 通過(guò)向它的 delegate 發(fā)送 actionForLayer:forKey: 消息來(lái)詢問(wèn)提供一個(gè)對(duì)應(yīng)屬性變化的 action垛吗。delegate 可以通過(guò)返回以下三者之一來(lái)進(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羡儿;
總結(jié)
總接來(lái)說(shuō)就是如下幾點(diǎn):
每個(gè) UIView 內(nèi)部都有一個(gè) CALayer 在背后提供內(nèi)容的繪制和顯示礼患,并且 UIView 的尺寸樣式都由內(nèi)部的 Layer 所提供。兩者都有樹(shù)狀層級(jí)結(jié)構(gòu)掠归,layer 內(nèi)部有 SubLayers缅叠,View 內(nèi)部有 SubViews.但是 Layer 比 View 多了個(gè)AnchorPoint
在 View顯示的時(shí)候,UIView 做為 Layer 的 CALayerDelegate,View 的顯示內(nèi)容由內(nèi)部的 CALayer 的 display
CALayer 是默認(rèn)修改屬性支持隱式動(dòng)畫(huà)的拂到,在給 UIView 的 Layer 做動(dòng)畫(huà)的時(shí)候痪署,View 作為 Layer 的代理,Layer 通過(guò) actionForLayer:forKey:向 View請(qǐng)求相應(yīng)的 action(動(dòng)畫(huà)行為)
layer 內(nèi)部維護(hù)著三分 layer tree,分別是 presentLayer Tree(動(dòng)畫(huà)樹(shù)),modelLayer Tree(模型樹(shù)), Render Tree (渲染樹(shù)),在做 iOS動(dòng)畫(huà)的時(shí)候兄旬,我們修改動(dòng)畫(huà)的屬性狼犯,在動(dòng)畫(huà)的其實(shí)是 Layer 的 presentLayer的屬性值,而最終展示在界面上的其實(shí)是提供 View的modelLayer
兩者最明顯的區(qū)別是 View可以接受并處理事件,而 Layer 不可以领铐。