1. 程式人生 > >iOS --- UIView與CALayer的聯絡與區別

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 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/重點內容

相關推薦

UIViewCALayer有什麼區別聯絡

在 iOS 中,所有的 view 都是由一個底層的 layer 來驅動的。view 和它的 layer 之間有著緊密的聯絡,view 其實直接從 layer 物件中獲取了絕大多數它所需要的資料。在 iOS 中也有一些單獨的 layer,比如 AVCaptureV

Java基礎:&&&,|| |的聯絡區別(詳解及示例)

&與&& 的聯絡與區別 一、&與&&的相同點   &與&& 都可作為 邏輯“與”的運算,即當運算子兩邊表示式結果都為True時,運算結果返回True;否則當某一表達式為False時,運算結果返回False 。

source export聯絡使用

shell與export命令使用者登入到Linux系統後,系統將啟動一個使用者shell。在這個shell中,可以使用shell命令或宣告變數,也可以建立並執行shell指令碼程式。執行shell指令碼程式時,系統將建立一個子shell。此時,系統中將有兩個shell,一個是

iOS UIViewCALayer 的關係

一、概念: UIView不具備顯示功能,擁有顯示功能的是它內部的圖層即CALayer屬性 當UIView需要顯示到螢幕上時,會呼叫DrawRect:方法進行繪圖,並且將所有的內容繪製在自己的圖層上Property()CALayer *layer,繪圖完成後,

iOS --- UIViewCALayer聯絡區別

UIView是iOS系統中介面元素的基礎, 所有的介面元素都繼承自它, UIView本身完全是由CoreAnimation來實現. 真正的繪圖部分, 是由一個CALayer類來管理. UIView更像是一個CALayer的管理器, 所以訪問它的與繪圖和座標相關的

UIViewCALayer區別

1、UIView是IOS系統中介面元素的基礎,所有的介面元素都繼承自它。它本身完全是由CoreAnimation來實現的(Mac下似乎不是這樣)。它真正的繪圖部分是由一個叫CALayer(Core Animation Layer)的類來管理。UIView本身,更像是一個CA

hashCodeequals的聯絡區別

一、equals方法的作用 1、預設情況(沒有覆蓋equals方法)下equals方法都是呼叫Object類的equals方法,而Object的equals方法主要用於判斷物件的記憶體地址引用是不是同一個地址(是不是同一個物件)。 2 、要是類中覆蓋了equals方法,那麼就要根據具

Linux curlwget 命令的區別聯絡

        當想要直接通過 Linux 命令列下載檔案,馬上就能想到兩個工具:wget 和 curl。它們有很多一樣的特徵,可以很輕易的完成一些相同的任務。      &n

反捲積、上取樣、上池化的聯絡區別

FCN於反捲積(Deconvolution)、上取樣(UpSampling) https://blog.csdn.net/nijiayan123/article/details/79416764 反捲積(Deconvolution)、上取樣(UNSampling)與上池化(UnPooling

ARM "重定位" "分散載入" 之間的聯絡區別

目前剛剛學完了ARM的裸機部分,有一個問題一直比較困惑:就是 “重定位” 和 “分散載入” 到底是什麼關係? 首先結合S5PV210的啟動方式,iROM(BL0)中的程式執行完之後,將BL1(16K)從SD卡中複製到SRAM中執行,然後把BL2(剩餘的程式)複製到DDR中去執行。把B

java List 、Set 、Map集合聯絡區別

List Map Set 集合 一、基礎概念 1. Collection 和 Map 介面 ​ Java集合框架主要由 Collection和Map兩個根介面及其子介面、實現類組成。 ​ 1) Collection 介面是Set、List、和Queue介面的父介面: ​ Coll

iOS開發知識之:pod installpod update的區別

引言 許多使用cocoapod的人認為pod install只在第一次使用CocoaPod設定專案的時候使用,pod update是在設定完專案之後使用的,但事實並非如此。 這篇指南將會說明什麼時候應該使用pod install,什麼時候應該使用pod update。 如果你覺得這篇指南太過於

C#中的虛方法、抽象方法、抽象類、介面的聯絡區別

虛方法的關鍵字是virtual抽象方法的關鍵字是abstract重寫都是override 虛方法也可以new虛方法和抽象方法的區別:虛方法:可以在抽象類和非抽象類中定義,可以寫在父類中,在子類中可以被重寫,在定義虛方法時必須實現虛方法 (在定義虛方法時需要寫實現方法的程式碼或者至少

Makefile和Cmake的聯絡區別

CMake是一種跨平臺編譯工具,比make更為高階,使用起來要方便得多。CMake主要是編寫CMakeLists.txt檔案,然後用cmake命令將CMakeLists.txt檔案轉化為make所需要的makefile檔案,最後用make命令編譯原始碼生成可執行程式或共享庫(so(shared ob

Constructor&object 的聯絡區別

constructor&object 的聯絡與區別 建構函式與物件 建構函式是類中的特殊成員函式,用於為物件分配記憶體。它可用於為資料成員提供值。建立物件時將呼叫建構函式。它與類具有相同的名稱。建構函式不返回任何值。 建構函式是生成物件的模板,一個建構函式可以生成多個物件,每個物件都有相同的結構

結構體物件的聯絡區別

結構體與物件的聯絡與區別 1.結構體是一種值型別,而類是引用型別。值型別用於儲存資料的值,引用型別用於儲存對實際資料的引用。 那麼結構體就是當成值來使用的,類則通過引用來對實際資料操作。   2.結構使用棧儲存(Stack Allocation),而類使用堆儲存(Heap Allocatio

C和C++的聯絡區別

面向過程的思路:分析解決問題所需的步驟,用函式把這些步驟依次實現。 面向物件的思路:把構成問題的事務分解為各個物件,建立物件的目的,不是完成一個步驟,而是描述某個事務在解決整個問題步驟中的行為。 從上述描述可以看出,其實面向物件和麵向過程是兩種思考解決問題的方式,其差異主要在於思考的角度。

記憶體溢位記憶體洩露的區別聯絡,如何檢測、解決

記憶體溢位 out of memory,是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是記憶體溢位 記憶體洩露 memory leak,是指程式在申請記

RNN,LSTM和GRU和word2vec及embedding等的聯絡區別解析。

普通的MLP和CNN都沒有事件維度,可以從RNN開始引入了事件維度,這在理解上給我們帶來了一些困難,筆者為了避免遺忘,將這種區別和特點記錄如下。 (沒時間畫圖,就看文字吧,寫的比較簡單。。。) 資料 https://zhuanlan.zhihu.com/p/36455374 這

一級域名(頂級域名),二級域名,主域名,次域名聯絡區別及域名帶不帶www的區別

相關參考文件 域名概念: (英語:Domain Name),簡稱域名、網域,是由一串用點分隔的名字組成的Internet上某一臺計算機或計算機組的名稱,用於在資料傳輸時標識計算機的電子方位(有時也指地理位置)。 頂級域名(也叫一級域名,即倒數第一個點的右邊): ***通用頂級域*