UIKit
UIKit
是iOS開發最經常使用的框架,能夠經過設置UIKit
組件的佈局以及相關屬性來繪製界面。
事實上,UIKit
自身並不具有在屏幕成像的能力,其主要負責對用戶操做事件的響應(UIView
繼承自UIResponder
),事件響應的傳遞大致是通過逐層的視圖樹遍歷實現的。ios
Core Animation
Core Animation
源自於Layer Kit
,動畫只是Core Animation
的冰山一角。 Core Animation
是一個複合引擎,其職責是儘量快地組合屏幕上不一樣的可視內容,這些可視內容可被分解成獨立的圖層(即CALayer),這些圖層會被存儲在一個叫作圖層樹的體系之中。從本質上而言,CALayer
是用戶所能在屏幕上看見的一切的基礎。緩存
Core Graphics
Core Graphics
基於Quartz
高級繪圖引擎,主要用於運行時繪製圖像。開發者可使用此框架來處理基於路徑的繪圖,轉換,顏色管理,離屏渲染,圖案,漸變和陰影,圖像數據管理,圖像建立和圖像遮罩以及PDF文檔建立,顯示和分析。bash
當開發者須要在運行時建立圖像時,可使用Core Graphics
去繪製。與之相對的是運行前建立圖像,例如用Photoshop提早作好圖片素材直接導入應用。相比之下,咱們更須要Core Graphics
去在運行時實時計算、繪製一系列圖像幀來實現動畫。app
Core Image
Core Image
與Core Graphics
偏偏相反,Core Graphics
用於在運行時建立圖像,而Core Image
用於處理運行前建立的圖像。Core Image
框架擁有一系列現成的圖像過濾器,能對一寸照的圖像進行高效的處理。
大部分狀況下,Core Image
會在GPU中完成工做,若是GPU忙,會使用CPU進行處理。框架
OpenGL ES
OpenGL ES
是OpenGL
的子集。在圖形渲染原理一文中提到過OpenGL
是一套第三方標準,函數的內部實現由對應的GPU廠商開發實現。OpenGL / OpenGL ES
入門篇,請參考OpenGL/OpenGL ES 入門:圖形API以及專業名詞解析等系列文章函數
CALayer
事實上是用戶所能在屏幕上看見的一切的基礎。爲何UIKit
中的視圖可以呈現可視化內容,就是由於UIKit
中的每個UI視圖控件其實內部都有一個關聯的CALayer
,即backing layer
。
因爲這種一一對應的關係,視圖層級有用視圖樹的樹形結構,對應CALayer
層級也擁有圖層樹的樹形結構。oop
其中,視圖的職責是建立並管理圖層,以確保當子視圖在層級關係中添加或被移除時,其關聯的圖層在圖層樹中也有相同的操做,即保證視圖樹和圖層樹在結構上的一致性。佈局
爲何iOS要基於UIView和CALayer提供兩個平行的層級關係呢?post
其緣由在於要作職責分離,這樣也能避免不少重複代碼。在iOS和Mac OSX兩個平臺上,事件和用戶交互有不少地方的不一樣,基於多點觸控的用戶界面和基於鼠標鍵盤的交互有着本質的區別,這就是爲何iOS有UIKit
和UIView
,對應Mac OSX有AppKit
和NSView
的緣由。它們在功能上很類似,可是在實現上有着顯著的區別。動畫
實際上,這裏並非兩個層級關係,而是四個。每個都扮演着不一樣的角色。除了視圖樹和圖層樹,還有呈現樹和渲染樹。
CALayer
那麼爲何CALayer
能夠呈現可視化內容呢?由於CALayer
基本等同於一個紋理。紋理是GPU進行圖像渲染的重要依據。
在圖形渲染原理中提到紋理本質上就是一張圖片,所以CALayer
也包含一個contents
屬性指向一塊緩存區,稱爲backing store
,能夠存放位圖(Bitmap)。iOS中將該緩存區保存的圖片稱爲寄宿圖。
圖形渲染流水線支持從頂點開始進行繪製(在流水線中,頂點會被處理生成紋理),也支持直接使用紋理(圖片)進行渲染。相應地,在實際開發中,繪製界面也有兩種方式: 一種是手動繪製;另外一種是使用圖片。
對此,iOS中也有兩種相應的實現方式:
Contents Image
Contents Image
是指經過CALayer
的contents
屬性來配置圖片。然而,contents
屬性的類型爲id
,在這種狀況下,能夠給contents
屬性賦予任何值,app仍能夠編譯經過。可是在實踐中,若是contents
的值不是CGImage
,獲得的圖層將是空白的。
既然如此,爲何要將contents
的屬性類型定義爲id
而非CGImage
。由於在Mac OS系統中,該屬性對CGImage
和NSImage
類型的值都起做用,而在iOS系統中,該屬性只對CGImage
起做用。
本質上,contents
屬性指向的一塊緩存區域,稱爲backing store
,能夠存放bitmap數據。
Custom Drawing
Custom Drawing
是指使用Core Graphics
直接繪製寄宿圖。實際開發中,通常經過繼承UIView
並實現-drawRect:
方法來自定義繪製。
雖然-drawRect:
是一個UIView
方法,但事實上都是底層的CALayer
完成了重繪工做並保存了產生的圖片。 下圖所示爲drawRect:
繪製定義寄宿圖的基本原理
UIView
有一個關聯圖層,即CALayer
。CALayer
有一個可選的delegate
屬性,實現了CALayerDelegate
協議。UIView
做爲CALayer
的代理實現了CALayerDelegate
協議。-drawRect:
,CALayer
請求其代理給予一個寄宿圖來顯示。CALayer
首先會嘗試調用-displayLayer:
方法,此時代理能夠直接設置contents
屬性。- (void)displayLayer:(CALayer *)layer;
複製代碼
-displayLayer:
方法,CALayer
則會嘗試調用-drawLayer:inContext:
方法。在調用該方法前,CALayer
會建立一個空的寄宿圖(尺寸由bounds
和contentScale
決定)和一個Core Graphics
的繪製上下文,爲繪製寄宿圖作準備,做爲ctx
參數傳入。- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
複製代碼
Core Graphics
繪製生成的寄宿圖會存入backing store
。介紹一下Core Animation
流水線的工做原理:
Render Server
進程。
App經過IPC將渲染任務及相關數據提交給Render Server
。Render Server
處理完數據後,再傳遞至GPU。最後由GPU調用iOS的圖像設備進行顯示。
Core Animation
流水線的詳細過程以下:
Render Server
,即完成了一次commit Transaction
操做。Render Server
主要執行OpenGL、Core Graphics相關程序,並調用GPU。Frame Buffer
、視頻控制器等相關部件,將圖像顯示在屏幕上。對上述步驟進行串聯,他們執行所消耗的時間圓圓超過16.67ms,所以爲了知足對屏幕的60FPS刷新率的支持,須要將這些步驟進行分解,經過流水線的方式並行執行,以下圖:
Commit Transaction
在Core Animation
流水線中,app調用Render Server
前的最後一步Commit Transaction
其實能夠細分爲4個步驟:
Layout
Display
Prepare
Commit
Layout
Layout
階段主要進行視圖構建,包括:LayoutSubviews
方法的重載,addSubview:
方法填充子視圖等。
Display
Display
階段主要進行視圖繪製,這裏僅僅是設置成像的圖元數據。重載視圖的drawRect:
方法能夠自定義UIView
的顯示,其原理是在drawRect:
方法內部繪製寄宿圖,該過程使用GPU和內存。
Prepare
Prepare
階段屬於附加步驟,通常處理圖像的解碼和轉碼等操做。
Commit
commit
階段主要將圖層進行打包,並將它們發送至Render Server
。該過程會遞歸執行,由於圖層和視圖都是以樹形結構存在。
iOS動畫的渲染也是基於上述Core Animation
流水線完成的。這裏咱們重點關注app與Render Server
的執行流程。
平常開發中,若是不是特別的複雜動畫,通常使用UIView
Animation實現,iOS將其處理過程分爲以下三部階段:
animationWithDuration:animations:
方法Layout,Display,Prepare,Commit
等步驟。Render Server
根據Animation逐幀進行渲染。參考博客 iOS圖像渲染原理