你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 詳解 CALayer 和 UIView 的區別和聯系

詳解 CALayer 和 UIView 的區別和聯系

編輯:IOS開發基礎

pexels-photo-large.jpeg

作者:@武蘊牛x 授權本站轉載。

前言

前面發了一篇iOS 面試的文章,在說到 UIView 和 CALayer 的區別和聯系的時候,被喵神指出沒有切中要點,所以這裡就 CALayer 和 UIView 這個問題重新整理了下。這裡會先分條解釋,最後會在文章的結尾給出概括性總結。

1.首先UIView可以響應事件,Layer不可以.

UIKit使用UIResponder作為響應對象,來響應系統傳遞過來的事件並進行處理。UIApplication、UIViewController、UIView、和所有從UIView派生出來的UIKit類(包括UIWindow)都直接或間接地繼承自UIResponder類。

在 UIResponder中定義了處理各種事件和事件傳遞的接口, 而 CALayer直接繼承 NSObject,並沒有相應的處理事件的接口。

下面列舉一些處理觸摸事件的接口

  • – touchesBegan:withEvent:

  • – touchesMoved:withEvent:

  • – touchesEnded:withEvent:

  • – touchesCancelled:withEvent:

其實還有一些運動和遠程控制事件等等,這裡就不一一列舉了。

下面的兩篇文章詳細介紹了 iOS 事件的處理和傳遞

參考鏈接:

  • http://blog.csdn.net/chun799/article/details/8223612

  • http://yishuiliunian.gitbooks.io/implementate-tableview-to-understand-ios/content/uikit/1-1-2.html

2.View和CALayer的Frame映射及View如何創建CALayer.

一個 Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform 共同決定的,而一個 View 的 frame 只是簡單的返回 Layer的 frame,同樣 View 的 center和 bounds 也是返回 Layer 的一些屬性。(PS:center有些特列)為了證明這些,我做了如下的測試。

首先我自定義了兩個類CustomView,CustomLayer分別繼承 UIView 和 CALayer

在 CustomView 中重寫了

+ (Class)layerClass
{
    return [CustomLayer class];
}
- (void)setFrame:(CGRect)frame
{
    [super setFrame:frame];
}
- (void)setCenter:(CGPoint)center
{
    [super setCenter:center];
}
- (void)setBounds:(CGRect)bounds
{
    [super setBounds:bounds];
}

同樣在 CustomLayer中同樣重寫這些方法。只是 setCenter方法改成setPosition方法

我在兩個類的初始化方法中都打下了斷點

blob.png

首先我們會發現,我們在 [view initWithFrame] 的時候調用私有方法【UIView _createLayerWithFrame】去創建 CALayer。

然後我在創建 View 的時候,在 Layer 和 View 中Frame 相關的所有方法中都加上斷點,可以看到大致如下的調用順序如下

[UIView _createLayerWithFrame]
[Layer setBounds:bounds]
[UIView setFrame:Frame]
[Layer setFrame:frame]
[Layer setPosition:position]
[Layer setBounds:bounds]

我發現在創建的過程只有調用了 Layer 的設置尺寸和位置的然而並沒有調用View 的 SetCenter 和 SetBounds 方法。

然後我發現當我修改了 view的 bounds.size 或者 bounds.origin 的時候也只會調用上邊 Layer的一些方法。所以我大膽的猜一下,View 的 Center 和 Bounds 只是直接返回layer 對應的 Position 和 Bounds.

View中frame getter方法,bounds和center,UIView並沒有做什麼工作;它只是簡單的各自調用它底層的CALayer的frame,bounds和position方法。

關於 Frame 的理解參考:http://www.cocoachina.com/industry/20131209/7498.html

3.UIView主要是對顯示內容的管理而 CALayer 主要側重顯示內容的繪制。

我在 UIView 和 CALayer 分別重寫了父類的方法。

[UIView drawRect:rect]//UIView    
[CALayer display]//CALayer

然後我在上面兩個方法加了斷點,可以看到如下的執行。

blob.png

可以看到 UIView 是 CALayer 的CALayerDelegate,我猜測是在代理方法內部[UIView(CALayerDelegate) drawLayer:inContext]調用 UIView 的 DrawRect方法,從而繪制出了 UIView 的內容.

4.在做 iOS 動畫的時候,修改非 RootLayer的屬性(譬如位置、背景色等)會默認產生隱式動畫,而修改UIView則不會。

對於每一個 UIView 都有一個 layer,把這個 layer 且稱作RootLayer,而不是 View 的根 Layer的叫做 非 RootLayer。我們對UIView的屬性修改時時不會產生默認動畫,而對單獨 layer屬性直接修改會,這個默認動畫的時間缺省值是0.25s.

在 Core Animation 編程指南的 “How to Animate Layer-Backed Views” 中,對為什麼會這樣做出了一個解釋:

UIView 默認情況下禁止了 layer 動畫,但是在 animation block 中又重新啟用了它們

是因為任何可動畫的 layer 屬性改變時,layer 都會尋找並運行合適的 'action' 來實行這個改變。在 Core Animation 的專業術語中就把這樣的動畫統稱為動作 (action,或者 CAAction)。

layer 通過向它的 delegate 發送 actionForLayer:forKey: 消息來詢問提供一個對應屬性變化的 action。delegate 可以通過返回以下三者之一來進行響應:

  1. 它可以返回一個動作對象,這種情況下 layer 將使用這個動作。

  2. 它可以返回一個 nil, 這樣 layer 就會到其他地方繼續尋找。

  3. 它可以返回一個 NSNull 對象,告訴 layer 這裡不需要執行一個動作,搜索也會就此停止。

當 layer 在背後支持一個 view 的時候,view 就是它的 delegate;

這部分的具體內容參考:http://objccn.io/issue-12-4/

總結

總接來說就是如下幾點:

  • 每個 UIView 內部都有一個 CALayer 在背後提供內容的繪制和顯示,並且 UIView 的尺寸樣式都由內部的 Layer 所提供。兩者都有樹狀層級結構,layer 內部有 SubLayers,View 內部有 SubViews.但是 Layer 比 View 多了個AnchorPoint

  • 在 View顯示的時候,UIView 做為 Layer 的 CALayerDelegate,View 的顯示內容由內部的 CALayer 的 display

  • CALayer 是默認修改屬性支持隱式動畫的,在給 UIView 的 Layer 做動畫的時候,View 作為 Layer 的代理,Layer 通過 actionForLayer:forKey:向 View請求相應的 action(動畫行為)

  • layer 內部維護著三分 layer tree,分別是 presentLayer Tree(動畫樹),modeLayer Tree(模型樹), Render Tree (渲染樹),在做 iOS動畫的時候,我們修改動畫的屬性,在動畫的其實是 Layer 的 presentLayer的屬性值,而最終展示在界面上的其實是提供 View的modelLayer

  • 兩者最明顯的區別是 View可以接受並處理事件,而 Layer 不可以

參考鏈接

  • http://blog.csdn.net/weiwangchao_/article/details/7771538

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved