IOS核心動畫高級一:圖層樹

圖層樹

先來介紹幾個我們常見的名詞:
Core Animation:只看它的名字會讓人產生一種誤解——核心動畫。從功能方面來看這並不能體現他的強大之處,Core Animation 是從一個Layer Kit 的庫演變而來的(當然 Layer Kit 這個名字就不會讓我們直接聯想到動畫相關了),動畫對 Core Animation 來說只是其中的一部分。

Core Animation 是一個複合引擎,它的職責就是儘可能快的組合屏幕上不同的可視內容,這個內容是被分解成獨立的圖層,存儲在一個叫做圖層樹的體系之中。於是這個樹形成了UIKit 和在ios應用程序中你所能在屏幕上看見的一切內容的基礎。

在開始核心動畫之前,我們先從圖層樹開始,瞭解一些 Core Animation 的靜態組合和“佈局特性”。

圖層與視圖

視圖——UIView

如果你在ios應用程序的開發經驗,對視圖概念應該是比較熟悉,一個視圖就是一個屏幕上顯示的矩形塊(比如圖片,視頻、文字),同時它能夠攔截類似鼠標點擊或者觸摸手勢等的用戶輸入。視圖在層級關係中可以互相嵌套,一個視圖可以管理它所有子視圖的位置。

1.1——左邊是ios屏幕顯示效果,右邊是形成視圖的層級關係.jpeg

在 ios 中所有的視圖都是從 UIView 基類中派生出來的,UIView 可以處理觸摸事件,可以支持基於 Core Graphics 的繪製,可以做仿射變換(例如旋轉或者縮放),或者簡單的類似於滑動(frame)或者漸變(alpha)的動畫

圖層——CALayer

CALayer 和 UIView 在概念上類似,同樣也是一些被層級關係樹管理的矩形塊,同樣也包含一些內容(比如圖片,文字,背景色),同樣它也管理他所有的子圖層的位置,它們也有一些方法和屬性用來做動畫和變換。 和 UIView 最大的不同是:CALayer 不處理用戶的交互(類似鼠標點擊,觸摸手勢)

CALayer 並不清楚具體的響應鏈(ios 通過視圖層級關係用來傳遞觸摸事件的機制),所以它並不能夠響應事件,即使他提供了一些方法來判斷是否一個觸點在圖層範圍之內(後文有介紹)。

平行的層級關係

每一個 UIView 都有一個 CALayer 類型的圖層屬性。也就是所謂的 backing layer(永久層),視圖的職責就是創建並管理這個圖層,以確保子視圖在層級關係中添加或者刪除的時候,他們關聯的圖層也同樣對應在層級關係樹中有相同的操作

1.2——左邊是圖層的樹狀結構,右邊是對應的視圖層級

實際上這些背後關聯的圖層纔是真正用來在屏幕上顯示和做動畫的, UIView 僅僅是對它的一個封裝,提供了一些ios類似處理觸摸事件的一些具體功能。以及一些使用 Core Animation 底層方法的高級接口。

此時大家可能就有疑問:IOS爲什麼要基於 UIView 和 CALayer 提供兩套平行的層級關係呢?爲什麼不使用一個簡單的層級來處理所有的事情?好問題,原因在於 要做職責分離,這樣也能避免很多重複代碼。在 ios 和 macOS 兩個平臺上,事件和用戶交互有很多地方的不同,基於多點觸控的用戶界面和基於鼠標和鍵盤有着本質的區別,這就是爲什麼ios有 UIKit 和 UIView , MacOS 有AppKit 和 NSView 。他們在功能很相似,但是在實現上有着顯著的區別。

繪圖、佈局和動畫相比之下就是類似Mac 筆記本和桌面系列一樣應用於iPhone和iPad觸屏的概念。把兩個平臺上的這種功能的邏輯分開應用到獨立的 Core Animation 框架,使得蘋果的OS團隊和第三方開發者去開發兩個平臺的應用更加便捷。

實際上,這裏並不是兩個層級關係,而是四個,每一個都扮演不同的角色,除了視圖層級和圖層樹之外,還存在呈現樹渲染樹,我們在後面的介紹。

圖層CALayer的能力

如果說 CALayer 是 UIView 的內部實現細節,那 我們爲什麼還要費勁心思的瞭解他呢?當然蘋果位我們提供了優美簡潔的 UIView 的接口,那麼我們是否就沒有必要直接去處理 Core Animation 一些實現上的細節了呢?

在某種程度是確實是這樣,對一些簡單的需求來說,我們確實沒有必要處理 CALayer , 蘋果已經通過UIView 的高級API間接地使得動畫變得很簡單。

但是這種簡單不可避免的會帶來靈活上的一些缺陷、如果你略微想在底層做一些改變,或是想要使用一些蘋果沒有在 UIView 中實現的接口功能,這時候處了介入Core Animation底層之外 別無其他選擇。

我們已經證實了圖層不能像視圖那樣處理觸摸時間,那它能做那些視圖不能做的呢?舉例一些 UIView 沒有暴露出的 CALayer 功能。

  • 圓角,陰影,帶顏色的邊框
  • 3D的動畫變換
  • 非舉行範圍繪製。
  • 透明遮罩
  • 多級非線性動畫

跟着我們學習的腳步,我們會一一爲大家講解這些功能,但在此之前,我們首先要關注最基本的,CALayer 是如何被使用的。

使用圖層

我們使用代碼的形式進行演示,
創建項目的代碼我們就省去了,節約大家時間
項目創建完成

項目創建完成.png

首先我們在創建一個子視圖(layerView)添加到 viewController 的視圖上。
效果如下:

子視圖效果.png

然而這並沒有什麼卵用,
我們想要在白色的視圖中添加一個藍色的區域,當然你可以通過添加子視圖的方式實現,但這對我們的學習layer沒有什麼卵用。

因此我們通過創建圖層來完成。於是呢我們創建一個layer圖層,並且把它作爲我們視圖相關圖層的子圖層。儘管 UIView 的接口中暴露了圖層屬性,但是標準的Xcode項目幷包含Core Animation 的相關頭文件,所以如果我們不給項目添加合適的庫,是不能使用任何圖層相關的方法或者訪問他的屬性的。所以首先需要添加QuartzCore 框架到building phases下。
如圖所示:

添加庫.png

之後就可以在代碼中應用CALayer的屬性和方法了,我們創建一個Layer 設置藍色添加到layerView相關圖層的子圖層上,
代碼如下

UIView *layerView = [[UIView alloc] initWithFrame: CGRectMake(100, 100, 200, 200)];
layerView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:layerView];

//添加一個圖層
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(50, 50, 100, 100);
layer.backgroundColor = [UIColor blueColor].CGColor;
[layerView.layer addSublayer:layer];

咱們看效果:

看效果.png

一個視圖只有一個相關聯的圖層(自動創建),同時它也可以支持添加無數多個子圖層。從上面的例子我們可以看出,你可以顯示創建一個單獨的圖層。並且把它直接添加到視圖關聯圖層的子圖層。儘管可以這樣添加圖層,但往往我們只是簡單地處理視圖,他們關聯的圖層並不需要額外地手動添加子視圖。

額外補充:
在 MacOS平臺,10.8版本之前,一個顯著的性能缺陷就是 macOS 使用 UIView視圖層級而不在一個單獨的視圖內使用CALayer樹狀層級。但在IOS平臺,使用輕量級的 UIView類並沒有顯著的性能影響(當然在 MacOS 10.8系統之後,NSView 的性能有了很大的提升)

使用圖層關聯視圖層級而不是用CALayer的好處在於,你能在使用所有CALayer 底層特性的同時,也可以使用UIView提供的高級API (比如,自動排版、佈局,響應事件)

然而在以下場景,你可能更需要使用CALayer ,而不用使用UIView

  • 開發同時可以在Mac OS上運行的跨平臺應用。
  • 使用多種 CALayer 的子類,並且不想創建額外的 UIView 去封裝他們。
  • 做一些對性能特別挑剔的工作,(比如對 UIView 一些可忽略不計的操作都會引起性能方面顯著的不同,當然,你也可以直接使用 openGL繪圖)。
    當然這些場景比較少見,總體來說處理視圖還是比直接處理圖層方便一些。

文章總結:

我們文中闡述了圖層的樹狀結構。說明了如何在ios中由 UIView 的層級關係形成的一種平行的CALayer層級關係,後面使用Demo進行了演示。

未完待續……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章