iOS --- UIView與CALayer的聯絡與區別

來源:互聯網
上載者:User

iOS --- UIView與CALayer的聯絡與區別

UIView是iOS系統中介面元素的基礎, 所有的介面元素都繼承自它, UIView本身完全是由CoreAnimation來實現. 真正的繪圖部分, 是由一個CALayer類來管理. UIView更像是一個CALayer的管理器, 所以訪問它的與繪圖和座標相關的屬性, 如frame, bounds等, 實際上都是在訪問其所包含的CALayer的相關屬性. 因此, 可以在所有UIView的子類上實現動畫效果.
UIView繼承自UIResponder, 能接收並響應事件, 負責顯示內容的管理, 而CALayer繼承自NSObject, 不能響應事件, 負責顯示內容的繪製.

UIView的layer屬性

擷取UIView的layer屬性:

CALayer *layer = self.view.layer;

UIView的layerClass方法返回layer使用的類. 可以重寫該方法, 使UIView的繼承類使用指定的CALayer來顯示, 如下代碼可使其使用OpenGL來進行繪製.

+ (Class)layerClass {     return [CAEAGLLayer class];}

對於UIViewController, 可做如下操作讓其UIView使用OpenGL來繪製. CALayer的層級結構與UIView的類似, addSublayer與addSubview的作用類似.

CAEAGLLayer *eaglLayer = [CAEAGLLayer layer];eaglLayer.frame = self.view.frame;eaglLayer.opaque = YES;eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],kEAGLDrawablePropertyRetainedBacking,kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat, nil];[self.view.layer addSublayer:eaglLayer];

當CALayer有了更新, 而不能立即顯示, 可使用setNeedsDisplay方法來重繪顯示.

[myLayer setNeedsDisplay];// 更新局部地區[myLayer setNeedsDisplayInRect:CGRectMake(100,100,50,50)];// CoreGraphics可以直接使用renderInContext[myLayer renderInContext:UIGraphicsGetCurrent()];
CALayer

一個UIView可以有多個CALayer, UIView的尺寸樣式都是由內部的CALayer來提供的. 每一個CALayer顯示一種效果, 因此, 通過添加多種效果的CALayer, 以增強UIView的顯示能力. 如UIView自身不能設定圓角等效果, 而CALayer可設定邊框, 圓角, 陰影和變換變形等. 兩者都有樹狀層級結構, CALayer有subLayers, UIView有subViews.

contents屬性
CALayer *aLayer = [[CALayer alloc] init;aLayer.contents = [[UIImage imageNamed:@testImage] CGImage];aLayer.contentsGravity = kCAGravityResizeAspectFill;

這裡使用圖片給contents賦值的話, 一定要是CGImage.
可以通過設定contentsGravity設定其顯示模式, 相當於UIView的contentMode, 如kCAGravityResizeAspectFill 是鋪滿的 。kCAGravityResizeAspect 是顯示自己本身的大小 。
若果圖片超出CALayer 可以使用maskToBounds 進行裁剪 ,剪掉超出的部分 (配合圓角使用不錯)。

contentsRect

用來裁剪圖片, 預設的contentsRect是{0, 0, 1, 1}, 即整個圖都預設可見. 如果我們改成{0,0,0.5,0.5} 映像就就會被裁剪掉左上方的1/4.

CALayer效果
aLayer.backgroundColor = [[[UIColor redColor] colorWithAlphaComponent:0.2] CGColor];// 邊框aLayer.boardColor = [[UIColor blueColor] CGColor];aLayer.boardWidth = 2.0;// 圓角aLayer.cornerRadius = 10.0;// 陰影aLayer.shadowColor = [[UIColor greenColor] CGColor];aLayer.shadowOpacity = 0.5;aLayer.shadowOffset = CGSizeMake(2, 1);[self.view.layer addSublayer:aLayer];

圓角(cornerRadius)和陰影(shadowColor), 二者不能同時出現, 所以可以通過兩個重疊的UIView, 分別使其CALayer顯示圓角和陰影.

變換

QuartzCore的CATransform3D提供了旋轉,縮放和傾斜等變換效果.
添加3D或者仿射變換如下:

myView.layer.transform = CATransform3DMakeScale(-1.0, -1.0, 1.0);CGAffineTransform transform = CGAffineTransformMakeRotation(45.0);myView.layer.affineTransform = transform;

取消動畫可以使用[layer removeAllAnimations];
可參考swift詳解之二十四—————CoreAnimation(一)CALayer.

Layer Tree

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

UIView與CALayer的區別

UIView繼承自UIResponder,主要特點是可以響應觸摸事件。而CALayer是實際的圖層內容管理, 不會直接渲染到螢幕上。大家乾的的事情不一樣,是兩個東西,大家的存在互不影響,理所當然。

事件響應

簡單將CALayer視作只能顯示, 不能響應事件的特殊UIView; 或將UIView視作能接收和響應事件的CALayer.
UIKit使用UIResponder作為響應對象, 來響應系統傳遞過來的事件並進行處理.
UIApplication, UIViewController, UIView和所有從UIView派生出來的UIKit類(包括UIWindow)都直接或間接地繼承自UIResponder類. UIResponder中定義了處理各種事件和事件傳遞的介面.處理事件如touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:等.
CALayer直接繼承自NSObject, 並沒有相應的處理事件的介面.
關於UIResponder的更多內容請參考以下兩篇文章:
1. Responder Chain簡析
2. 視圖和視窗架構

frame, position, bounds調用

一個CALayer的frame是由其anchorPoint, position, bounds, transform共同決定的, 而一個UIView的的frame只是簡單地返回CALayer的frame, 同樣UIView的center和bounds也只是簡單返回CALayer的Position和Bounds對應屬性.

機制與策略分離

UIView主要是對顯示內容的管理, 而CALayer主要是顯示內容的繪製. UIView是CALayer的CALayerDelegate, 在代理方法內部[UIView(CALayerDelegate) drawLayer:inContext]調用UIView的drawRect方法, 從而繪製出UIView的內容. UIView的顯示內容由內部的CALayer:display方法來實現.
編程問題都可以抽離出機制和策略部分。機制一旦實現,就會很少更改,但策略會經常得到最佳化。CALayer也可以看做是一種機制,提供圖層繪製,CALayer的標頭檔基本上是沒怎麼變過的,而UIView可以看做是策略,變動很多。越是底層越是機制,越是機制就越是穩定。機制與策略分離,可以使得需要修改的代碼更少,特別是底層代碼,這樣可以提高系統的穩定性。UIView遮蔽了大部分的CALayer介面,抽取構造出更易用的frame和動畫實現,這樣上手更容易。

CALayer預設產生隱式動畫

CALayer預設修改屬性支援隱式動畫. 對於每一個 UIView 都有一個 layer,把這個 layer 且稱作RootLayer,而不是 View 的根 Layer的叫做 非 RootLayer。我們對UIView的屬性修改時時不會產生預設動畫,而對單獨 layer屬性直接修改會,這個預設動畫的時間預設值是0.25s. 即在做 iOS 動畫的時候,修改非 RootLayer的屬性(譬如位置、背景色等)會預設產生隱式動畫,而修改UIView則不會。
在給UIView的CALayer做動畫的時候, UIView作為CALayer的代理, CALayer通過actionForLayer:forKey:向UIView請求相應的動畫action.
在 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 可以通過返回以下三者之一來進行響應:
它可以返回一個動作對象,這種情況下 layer 將使用這個動作。
它可以返回一個 nil, 這樣 layer 就會到其他地方繼續尋找。
它可以返回一個 NSNull 對象,告訴 layer 這裡不需要執行一個動作,搜尋也會就此停止。
當 layer 在背後支援一個 view 的時候,view 就是它的 delegate;
這部分的具體內容參考:http://objccn.io/issue-12-4/重點內容

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.