天天看點

Core Animation學習總結

檔案夾:

  1. The Layer Beneath
  1. The Layer Tree(圖層樹)
  2. The Backing Image(寄宿層)
  3. Layer Geometry(圖層幾何學)
  4. Visual Effects(視覺效果)
  5. Transforms(變換)
  6. Specialized Layers(專有圖層)
  1. Setting Things in Motion
  1. Implicit Animations(隐式動畫)
  2. Explicit Animations(顯式動畫)
  3. Layer Time(圖層時間)
  4. Easing(緩沖)
  5. Timer-Based Animation(基于定時器的動畫)
  1. The Performance of a Lifetime
  1. Tuning for Speed(性能調優)
  2. Efficient Drawing(高效畫圖)
  3. Image IO(圖像IO)
  4. Layer Performance(圖層性能)

Core Animation 之 CALayer

1、圖層與視圖的差别:
  • 視圖是以樹的資料結構來管理層級關系的。而圖層相同也是以樹的資料結構來管理層級關系
  • 視圖在程式中以UIView及其子類來表示。而圖層以CALayer及其子類專用 圖層來表示
  • UIView總是與CALayer是一一相應的關系,是以本質上,iOS上界面上的内容的呈現與動态實際上是通過CALayer來實作的,而UIView是封裝了CALayer的基礎上加入了事件響應、布局等進階功能。
2、關于視圖層級、圖層樹、呈現樹、渲染樹
  • 視圖層級:主要負責實作事件響應、布局等功能,由于視圖封裝圖層。圖層向視圖暴露部分程式設計接口與屬性,于是通過改動視圖的效果能夠間接改動圖層的屬性。
  • 圖層樹:負責定義界面圖形的繪制、動畫效果,iOS是有一個繪制周期的——60FPS,也就是說圖層樹負責儲存這個周期内的相關屬性的改動,而到了周期結束要進行繪制的時候,才把圖層樹的資料模型更新到呈現樹中。
  • 呈現樹:确定目前螢幕上界面圖形的詳細效果。用于儲存目前螢幕的圖形的顯示屬性,每隔一個繪制周期和圖層樹同步一次。
  • 渲染樹:iOS系統會專門建立一個程序來運作圖形渲染的任務,當随意APP(包含系統App)須要圖形渲染的時間,它們就會把渲染任務發送到該線程去運作渲染。

是以以上四層。每一層都負責不同的任務,其資料流是視圖-》圖層-》呈現樹-》渲染樹。

而且繪制周期60FPS也是會随着系統的狀态而變化的,若系統資源超載,而會通過降低繪制次數來確定系統能穩定執行。

3、視圖動畫

視圖動畫是顯式,由于UIView預設把CALayer的隐式動畫禁止掉了。是以要通過動畫Block的形式才幹取消動畫的限制。(動畫block實際上就是曾經的動畫棧)。

而且視圖能實作的動畫僅僅是圖層所開放的一部分,都是2D動畫,是以視圖動畫的效果會稍稍簡單。

4、圖層動畫

圖層動畫是隐性動畫。僅僅要改動圖層的屬性。其變化都會以預設的漸變形式呈現出來(詳細原理見《隐式動畫》)。而且圖層動畫支援很多其它視圖動畫無法實作的效果。如:

  • 陰影、圓角、帶顔色的邊框
  • 3D變化
  • 非矩形範圍
  • 透明遮罩
  • 多級非線性動畫。

5、更适宜使用CAlayer呈現内容的場景

由于UIView與CALayer都能夠呈現内容。盡管CALayer不能直接實作事件響應。但開發人員也能夠通過hit-test機制的原理來自己實作事件響應,那什麼場景更加适合用CALayer而不是UIView呢?例如以下所看到的:

  • 開發同一時候能夠在MAC、iOS上執行的跨平台應用
  • 使用多種CALayer的子類(專有圖層),而且不想建立額外的UIView去封裝
  • 做一些對性能特别挑剔的工作,如對UIView一些可忽略不計的操作都會引起顯著的不同(也能夠通過OpenGL來解決)。

1、寄宿層&Contents屬性

CALayer有一個名曰Contents的屬性,這個屬性是與寄宿層相相應了,而contents屬性指向的對象必須為CGImageRef類型(一個指向CGImage結構的指針),是以寄宿層是用來展示圖檔所用的。例如以下情況會調用寄宿層:

  • 顯示圖檔
  • core Graphics

core Graphics能夠實作自己定義繪制,但通常不建議那麼做,由于core Graphics繪制會預設生成一個繪制專用的存儲空間,而這空間有十多M那麼多。會占用大量記憶體,是以Apple不建議實作空的core Graphics更不建議在core Graphics實作不屬于該方法的代碼。

2、contentGravity屬性

與UIView的contentMode屬性相相應,用于調整圖檔的布局,支援一下常量值:

  • kCAGravityCenter
  • kCAGravityTop
  • kCAGravityBottom
  • kCAGravityLeft
  • kCAGravityRight
  • kCAGravityTopLeft
  • kCAGravityTopRight
  • kCAGravityBottomLeft
  • kCAGravityBottomRight
  • kCAGravityResize
  • kCAGravityResizeAspect
  • kCAGravityResizeAspectFill

3、contentsScale

contentsScale屬性定義了寄宿層的像素尺寸和視圖大小比例,預設是1.0(一個點一個像素),在retina螢幕得設定在2.0(一個點兩個像素)。在plus裝置上得裝置為3.0(一個點3個像素)。

但若contentGravity設定了如kCAGravityResizeAspectFill自己主動适配大小的屬性後,contentsScale會不起作用。是以不能依靠contentsScale來做縮放的操作,縮放還是得交給transform或者affineTransform。

3、maskToBounds

該屬性與UIView的clipsToBounds屬性相相應。都是應用于将超出圖層邊界的子圖層的内容進行裁剪。

這裡須要一點須要注意的,但我們實作radiusCorner時,實際上就是通過設定背景顔色來實作的。而與maskToBounds結合才是真正把邊角内容裁剪掉,但radiusCorner+maskToBounds結合使用會引發離屏渲染。是以在radiusCorner滿足要求。就不要再調用maskToBounds。

4、contentsRect

CALayer的contentsRect同意我們在圖層邊框内顯示寄宿圖的一個子域,而contentsRect是一個相對值屬性,如{0,0。1,1}表示整個寄宿圖,這樣的坐标系統也叫機關。例如以下簡述iOS下的三種坐标系統機關:

  • 點:點是虛拟的像素,也叫邏輯像素。在不同的裝置上一個點所代表的像素點是不一樣的。如普通螢幕一個點就是一個像素,而retina螢幕一個點就是兩個像素。
  • 像素:實際的實體像素坐标。
  • 機關:一種相對的坐标,優點就是應用相對值,友善移植。

contentsRect有一種經典的使用方法——image sprites(圖檔拼接,經常使用于遊戲),這種使用方法就是用來實作一次性載入多張圖檔的。由于每一張圖檔的使用前都要經過,載入——》壓縮——》呈現,的一個過程當中載入和壓縮是十分耗時的,載入消耗IO,壓縮算法的複雜會添加CPU的消耗,是以想遊戲這種App須要載入解壓大量的圖檔時,能夠把全部圖檔整合成一張圖檔來載入解壓,然後通過contentsRect裁剪出子圖,并顯示,能夠優化載入解壓的過程。

5、contentsCenter

contentsCenter的名字事實上有一點的誤導性,事實上際上與UIView的Stretching屬性相相應。用來實作寄宿層的縮放時的呈現效果。也是一個相對值機關。

6、customs drwaing

除了通過CGImage設定到contents的方式來實作寄宿層。還能夠通過Core Graphics來直接繪制寄宿層,但這樣的方式十分消耗記憶體不建議使用。

CALayer有一個可選的Delegate屬性。實作了CALayerDelegate,但CALayer須要又一次繪制,則調用它的displayLayer方法(與UIView的setNeedDispaly相相應),就會調用其代理方法drawLayer:inContext(與UIView的drawRect相相應)。

若在視圖層中,僅僅要使用者實作了drawRect那麼僅僅要螢幕須要又一次繪制那麼該方法都會被預設調用。

1、布局

UIView的三個重要布局屬性:frame、bounds、center

CALayer的三個重要的布局屬性:frame、bounds、position

能夠看出UIView與CALayer的布局屬性是一一相應的,而唯一有啥差別的就是錨點的命名,UIView為center,而CALayer為position,但錨點最開始都是默覺得圖形的中心。

當中frame實際上就是一個虛拟屬性,其由bounds與center/position計算所得。是以改動bounds與center/position也會影響到frame的數值。

還有不管是視圖還是圖層。在螢幕上不管怎麼變形,本質上其還是一個矩形。但在旋轉的情況下。frame的數值是會事實變動的,例如以下圖:

Core Animation學習總結
Core Animation學習總結

2、錨點

錨點屬性是用來指定圖層相對于父圖層的位置。也能夠了解為利用圖層的句柄。默覺得圖層的中心但也能夠改動。在圖層中改動了錨點會産生移動(隐性動畫),相同的錨點也是一個相對值。

例如以下。為錨點的實驗效果圖:

圖一:時分秒針直接以圖層的中點為錨點,由于旋轉時也以其為中心,效果例如以下:

Core Animation學習總結
圖二:将錨點改動成指針的尾端
Core Animation學習總結
圖三:改動錨點後的旋轉效果。
Core Animation學習總結

3、坐标系

由于每一個圖層都有自己的坐标系,是以CALayer也提供了一系列的方法用于一個點在不同的坐标系之間轉換,這些方法特别适合于子圖層與父圖層之間的坐标轉換。

Core Animation學習總結

事實上UIView與CALayer都有zPosition。但因為UIView隻支援2D變換,是以UIView的zPosition隻适合于用來作圖層的調整,但更加建議用UIView提供的視圖數組管理方法來調整視圖的繪制順序來調整。而CALayer的zPosition是一個重要的三維坐标系。

4、Hit Testing

Hit Testing是iOS中一個十分重要的機制,用于檢索點選了的目标圖示,與響應鍊條互相搭配的話。就會将終于目标圖示設定為第一響應者。Hit Testing提供了兩個核心的方法:

  • containPoint:(用于直接推斷某個點是否屬于某個圖層)
  • -hitTest(通過遞歸周遊子對象的方式來直接傳回目标圖層)

5、自己主動布局

對于UIView。通過UIView暴露出來的UIViewAutoresizingMask和NSLayoutConstraint來實作自己主動布局。

但對于CALayer,則須要手動來操作實作,當中最為簡單的方法就是實作CALayerDelegate的例如以下函數:

- (void)layoutSublayersOfLayer:(CALayer *)layer;

在該方法内依據目前layer的屬性來計算調整來實作自己主動布局。

由于CALayer實作自己主動布局不友善,是以這也是為什麼更加建議使用UIView來實作界面的建構。

Visual Effects(視覺效果)——本節探讨可以通過CALayer實作的附加視覺效果

1、圓角

CALayer有一個叫做cornerRadius的屬性控制圖層角的曲率,這個曲率僅僅影響背景顔色而不影響圖檔或者子圖檔。圓角的計算原理就是一個以CALayer的中點,曲率所設的半徑的原與矩形的交集就是目标圖形。

另一個名曰maskToBounds屬性,就是實作将圖層裡面邊界外的圖形所有分割丢棄。

是以通過cornerRadius+maskToBounds組合能夠實作圓角,但同一時候會引發離屏渲染,若是小量的離屏渲染還好,但如卷軸框的場景,開會有大量的離屏渲染的任務産生,就會嚴重影響性能,這一點也是注意優化的。詳細效果例如以下圖所看到的:

Core Animation學習總結

2、圖層邊框

通過設定CALayer的borderWidth與borderColor兩個屬性能夠改動邊框的效果。

效果例如以下:

Core Animation學習總結

3、陰影

陰影是一種能達到圖層深度暗示效果的裝飾。

CALayer提供下面參數來定制陰影的效果:

  • shadowOpacity:設定一個大于零的數值,那麼陰影就會顯示在圖層以下(默覺得0)。
  • shadowColor:設定陰影的顔色(預設黑色)
  • shadowOffset:設定陰影的偏移量(預設{0。-3})
  • shadowRadius:設定陰影模糊度,數值越大。陰影的模糊度越高(默覺得0)。曲率越大,陰影效果越明顯。
shadowRadius的設定效果圖例如以下:
Core Animation學習總結

有一點須要注意的,就是陰影的繪制是屬于離屏繪制。是比較效果資源的。是以一定要降低同一螢幕進行大量陰影繪制的情況。

4、陰影裁剪

圖層的陰影很多其它是繼承于内容的外形,而不是依據邊界和角半徑來确定。為了計算出陰影的形狀。core animation會将寄宿層也考慮在内。

但若直接maskToBounds來裁剪,會把陰影效果也裁減掉。

為了解決以上問題。能夠通過專門引入一個陰影圖層來解決,詳細效果例如以下:

圖一:直接maskToBounds裁剪會把陰影效果一并裁剪掉。

Core Animation學習總結
圖二:通過加入一個另外的陰影圖層在以下,然它來實作陰影。而詳細的内容圖層就直接maskToBounds裁剪。
Core Animation學習總結
圖三:終于既能實作裁剪,又能實作陰影。
Core Animation學習總結

PS:不管是陰影還是圓角裁剪都會引發離屏渲染,大量的該類型的圖形須要渲染的話。會減低幀率。

5、shadowPath 屬性

陰影并一定是方形的。我們也能夠通過shadowPath來定制自己想要的陰影形狀。詳細效果例如以下所看到的:

Core Animation學習總結

6、圖層蒙版

通過masksToBounds屬性。我們能夠實作邊界裁剪,但我們還須要更加靈活的裁剪需求的時候就能夠通過圖層蒙版來實作。CALayer提供一個mask的屬性來解決一個問題。而mask本來就是指向還有一個圖層的指針。其詳細原理例如以下圖所看到的:

Core Animation學習總結
Core Animation學習總結

從上圖效果能夠知道mask舒心僅僅關心形狀的交集,而顔色還是由原來的圖形的顔色決定。

另一點須要注意的是圖層蒙版也會引發離屏渲染,會帶來性能問題,是以使用的時候也得多加注意。

7、拉伸過濾

當我們視圖顯示一個圖檔的時候。都應該以正确的比例,正确的1:1像素顯示在螢幕上。原因例如以下:

  • 可以顯示更好的畫質,像素既沒有被壓縮也沒有被拉伸
  • 能更好使用記憶體,由于這就是你要存儲的東西
  • 最好的性能表現,CPU不須要為此額外的計算 

但有時候我們就須要縮略圖。所專門另外存儲縮略圖這對記憶體來說。

這時就能夠通過CALayer的minificationFilter(縮小濾波器)和magnificationFilter(方法濾波器)屬性實作圖形的縮放算法。當中提供下面三種預設的縮放算法:

  • kCAFilterLinear(雙線性濾波算法,預設算法)
  • kCAFilterTrilinear(三線性濾波算法)
  • kCAFilterNearest(近期濾波算法)

對于大圖的縮放,採用kCAFilterLinear、kCAFilterTrilinear,效果會比較好。

對于小圖、較少斜線的圖的縮放,。採用kCAFilterNearest效果比較好。

圖一:採用kCAFilterLinear的方法濾波器算法的效果。

Core Animation學習總結
圖二:採用kCAFilterNearest的放大濾波器算法的效果:
Core Animation學習總結

8、透明組

UIView有一個alpha屬性類确定視圖的透明度。而CALayer有一個與之相應的屬性——opacity。這兩個屬性都會影響到子圖層。例如以下圖所看到的:

當我們将view2的alpha數值設定為0.5,這時候,對于label所處的點的顔色計算公式為:50%label + 25%view + 25%background,是以就是灰色偏白的顔色。

若想整個圖層的色調保持一緻,能夠通過将shouldRasterize屬性設定為YES,那麼圖層及其子圖層将被整合成一個總體的圖檔。效果例如以下:

圖一:shouldRasterize屬性設定為預設值NO的效果。

Core Animation學習總結
圖二:shouldRasterize屬性設定為預設值YES的效果。
Core Animation學習總結

1、仿射變換

UIView相應的transfrom屬性是一個CGAffineTransfrom類型。用于實作二維空間旋轉、平移、縮放、斜切。

而CALayer的transform屬性是一個CATransforms3D。能應用3維空間進行旋轉、平移、縮放、斜切等效果。

當中,仿射變化的數學原理例如以下:

Core Animation學習總結
隻是iOS為了運算的友善。已經提供了三個标準方法分别用于實作旋轉、縮放。平移,而斜切得靠原生運算來實作。
Core Animation學習總結

當中有一點須要注意的,就是旋轉的angle是以弧度制為機關的。

iOS系統提供下面方法來實作混合變換,能同一下面的組合函數實作複雜的變形模式:

圖一:建立一個空的變換結構體。

Core Animation學習總結
圖二:不斷疊加變換結構體
Core Animation學習總結
圖三:直接将兩個變換結構體合并
Core Animation學習總結
剪切變換的效果與事實上現代碼:
Core Animation學習總結
Core Animation學習總結

2、3D變化

3D變化與2D變化是十分相似的,不同的僅僅是3D變換是3個次元的,加入了Z軸。其數學原理例如以下:

Core Animation學習總結
這樣的矩陣運算還是挺麻煩的。是以iOS系統提供給我們便捷的方法:
Core Animation學習總結
相同也會有變換疊加的方法,當中旋轉的時候一定要注意目前的旋轉的參考軸,順時針旋轉為正值,逆時針旋轉為負值。
Core Animation學習總結

3、透視投影

在真實的世界中,當物體遠離我們。因為視角的原因,其會變小。是以為了讓3D效果更佳真實,須要引入投影變換,盡管core animation并沒有提供給我們,但十分簡單,其數學實作例如以下:

Core Animation學習總結

僅僅要将m34 = -1/d, d= 500~1000,(d越小越失真,d越大透視效果越弱)。

圖3.1:沒實作透視投影的旋轉效果。

Core Animation學習總結
圖3.2:實作了透視投影的旋轉效果。
Core Animation學習總結

4、滅點

在人的視覺中。當物體離人越遠則會變得越小,當接近無窮遠的時候就會彙聚成一個不可見的點,這個點就叫滅點。現實生活中,這個點通常就是中心點,是以在程式中我們也要讓圖形的滅點集中在螢幕的中點,例如以下所看到的:

Core Animation學習總結

而實作方式則是。首先加入圖形的時候先以螢幕中點為錨點加入,然後通過transfrom來講圖層移動到恰當的位置。

5、sublayerTransform

sublayerTransform是一種将全部對應的配置統一設定到該圖層的全部子圖層的便捷屬性。

6、3D坐标下的圖層背面

在3D坐标下,圖層的背面也是會繪制的,并且是正面的鏡像。

我們能夠通過CALayer的doubleSided屬性來決定是否運作雙面繪制。

7、扁平化圖層

假設父圖層的坐标發生變換,那麼子圖層也會随着父圖層而進行相同的變換,如7.1圖所看到的。但有時我們僅僅想變換父圖層并不想變換子圖層。這時就得做相對變換來抵消掉父圖層的變換。讓視覺效果看起來子圖層是精巧的。例如以下圖所看到的:

圖7.1:2D相對旋轉理論圖

Core Animation學習總結
圖7.2:2D相對旋轉效果圖
Core Animation學習總結
圖7.3:3D相對旋轉理論圖
Core Animation學習總結
圖7.4:3D相對旋轉實際效果圖
Core Animation學習總結

我們能夠看出,在2D坐标系下。相對變換是合理的。但在3D坐标系下,相對變換的結果并不如預想的一樣,為什麼呢?

這是由于core Animation圖層盡管存在于3D空間之内,但并非每個圖層都存在于同一個3D空間之間。

而使用者是以目前window所在的3D坐标系為參考的,這時7.4圖的3D坐标系與window的已經不重合的,是以在我們的視覺裡面,就是看不到預想的效果,這就是圖層扁平化。

圖層扁平化讓core animation建立複雜的3D場景變得十分困難,由于非常難使用圖層樹去建立一個3D結構的層級關系——将全部的場景下的3D都保持同樣的3D坐标系。

隻是CALayer提供一個專用圖層——CATransformLayer來解決問題,全部加入到該圖層内的3D圖形都共享一個标準坐标系。

8、3D場景下的光亮和陰影

略。臨時不懂。

9、3D場景下的點選事件

在處理點選事件,一定要注意點選響應是由UIView中的圖層結構來決定的,而不是CALayer在螢幕上的呈現效果,是以得注意事件攔截的順序。

能夠通過設定userInteractionEnabled以及簡單的視圖覆寫來實作點選事件正确的傳遞。

1、CAShapeLayer

2、CATextLayer

3、CATransformLayer

4、CAGradientLayer

5、CAReplicatorLayer

6、CAScrollLayer

7、CATiledLayer

8、CAEmitterLayer

9、CAEAGLlayer

10、AVPlayerLayer

Core Animation 之 動畫

1、隐式動畫&事務

Core Animation基于一個如果,就是螢幕上的全部圖形都能夠做動畫,并且這樣的動畫不須要開發人員去設定,會自己主動實作。這也是為什麼直接改動CALayer的屬性會以一種漸變的形式來更新到一個新的值。

這樣的僅僅須要改動圖層的數值就會引發動畫的形式來更新到新數值的動畫稱為隐式動畫。

而這樣的定義了動畫的詳細呈現效果的機制,就稱為事務。

因為CALayer是預設開啟了隐式動畫的。而若我們在CALayer上調用顯式動畫的話,就考慮到隐式動畫對效果的影響,進而決定是否須要取消隐式動畫。

2、動畫Block

UIView封裝了CALayer。但UIView禁止了隐性動畫,是以開發人員須要在UIView上實作顯性動畫。

在iOS4.0之前,UIView採用動畫棧來管理顯示。後來提供了動畫Block這個更加便捷的方式。但原理都是一樣的。

3、圖層行為

我們把改變CALayer屬性時自己主動應用的動态稱為行為。一組行為的運作步驟例如以下所看到的:

  1. CALayer調用-actionForKey:方法,傳遞屬性名稱。
  2. 檢查CALayer是否持有實作了CALayerDelegate的代理對象(須要實作actionForLayer:forKey方法),若有直接調用并傳回結果,若無繼續下面步驟。
  3. 檢查包括屬性名稱相應行為映射的actions字典。若有則傳回,無則繼續
  4. 在style字典接着搜尋屬性名。若有這傳回,無則繼續
  5. 調用屬性的标準行為defaultActionForKey方法

經過以上的整個流程,要麼actionForKey傳回nil則無動畫效果,要麼就是傳回CAAction,然後CALayer利用它實作動畫。

是以能夠推動出UIView是怎樣禁止隐式動畫的,就是講CALayer的delegate設定為自身。然後在actionForLayer:forKey方法中傳回nil。

  • 禁止隐式動畫的兩個方法:
  • 依據圖層行為的原理,實作代理方法actionForLayer:forKey強制傳回nil。
  • 通過設定[CATransaction setDisableActions:YES]來實作禁止隐式動畫

4、呈現與模型

在iOS中。螢幕每秒鐘又一次重新整理螢幕60次。

是以Core Animaiton就須要在設定一次新值和新值生效之間,對螢幕上的圖層進行又一次組織。

正是以為上面的機制的存在。是以才會有iOS才會有圖層以及呈現層之間的關系,圖層更像是model,而呈現層就是view,Core Animation就是Controller,是以在一個繪制周期内,圖層負責收集與儲存使用者對屬性的改動,到繪制時刻時。就将圖層的資料覆寫到呈現樹。

我們能夠通過CALayer的 -presentationLayer方法來擷取正在螢幕上顯示的呈現樹的資料,盡管一般不須要。但在下面情況下會比較有作用

  • 做基于定時器的動畫時。而不不過基于事務的動畫。這時準備地知道目前時刻的圖層的顯示位置是十分實用的
  • 假設你想做圖層的響應輸入,能夠通過-hitTest方法來推斷制定圖層是否被觸摸。這時候對呈現圖層調用-hitTest會更加有效,由于呈現樹就是目前螢幕上的圖形實際的位置。
1、Core Animation的類圖架構
Core Animation學習總結
  • CAAnimation實作了CAMediaTiming協定。本身并沒有做什麼工作。主要實作動畫的時間相關的屬性以及計算函數(緩沖)
  • CATrasition描寫叙述變換的對象
  • CAAnimationGroup封裝屬性動畫的隊列。
  • CABasicAnimation基礎屬性動畫
  • CAKeyFrameAnimation關鍵幀動畫

2、基礎屬性動畫

基礎動畫主要由CABasicAnimation實作,由上圖可知道。而CABasicAnimation繼承于CAPropertyAnimation屬性動畫,通過設定下面三個數值以及其它的選項,就可以實作自己主動動畫:

  • fromValue
  • toValue
  • byValue

當中toValue與byValue不能同一時候使用,toVaule是絕對值,byValue是相對值。

屬性動畫都是針對關鍵幀的動畫。也就是說僅僅關心出發點與結束點,中間的過渡能夠自己生成也能夠預設。

3、關鍵幀動畫

CAKeyFrameAnimation用于實作關鍵幀動畫,能通過設定其animations數組來定義每一個關鍵幀的位置,也能夠直接通過path屬性來定義運動的路徑。

4、affineTransform屬性

若我們讓一個圖形沿着曲線運動。能夠通過設定affineTransform。讓其能沿着曲線的切線運動進而讓運動更加真實。前後效果圖例如以下圖所看到的:

Core Animation學習總結
Core Animation學習總結

5、虛拟屬性

屬性動畫實際上是針對關鍵路徑而不是一個鍵的。這就意味着能夠對子屬性甚至虛拟屬性做動畫。

如若我們想實作旋轉的效果,本來我們須要在keyPath上設定“transform”,

若使用虛拟屬性。能夠直接在keyPath上直接設定“transfrom.rotation”,這樣在設定formValue與toValue時就能夠直接設定弧度叫的值。

事實上transfrom.rotation這個屬性是并不存在的,而是core aniamiton自己主動依據CAValueFunction來又一次計算transform的數值所得,正由于如此才稱之為虛拟屬性。

6、動畫組

CAAnimationGroup是一種組合動畫的解決方式。通過CAAnimationGroup加入沿曲線運動與顔色變化的動畫。

Core Animation學習總結

7、過渡

略。

8、在動畫的過程中取消動畫

Core Animation提供了一部分的方法來實作動畫加入以及移除。例如以下圖所看到的:

​- (CAAnimation *)animationForKey:(NSString *)key;  //實作動畫的加入,當中key不僅能夠用來訪問動畫,還能夠用來移除動畫​

​- (void)removeAnimationForKey:(NSString *)key;  //移除Key指定的動畫​

​- (void)removeAllAnimations;  //移動CALayer已經加入的全部動畫​

1、CAMediaTiming協定

CAMediaTiming協定定義了在一段動畫内控制逝去時間的屬性集合。

CALayer和CAAnimaition都實作了該協定,是以時間能夠被随意圖層或者一段動畫的類所控制。

CAMediaTiming協定下定義的一些核心屬性:

  • duration:定義一段動畫的持續時間
  • repeatCount:定義一段動畫的反複次數
  • repeatDuration:制定動畫反複一段制定的時間
  • autoreverses:制定在每次間隔交替循環的過程中自己主動回放

能夠通過将repeatCount或者repeatDuration設定為INFINITY來實作動畫無限循環播放。但不能同一時候使用這兩個屬性。

2、相對時間

在Core Animation中,時間是相對的,每一個動畫都有自己的描寫叙述時間,能夠獨立的加速、延遲或者偏移,當中有下面關鍵屬性:

  • beginTime:動畫的開始時間。但不是絕對時間,而是一個相對時間,就是從該動畫加入到可見層的那一刻開始測量,預設是零。
  • speed:時間倍速,預設是1.0,若設定為2.0而二倍速前進。那麼對于一個duration為1.0的動畫,實際上0.5s就已經完畢。
  • timeOffset:讓動畫直接快進到某個時間點進行,使用它要注意是否有speed的參與而改變的duration
  • duration:動畫的播放時間。

3、fillMode

當一個圖層産生動畫,實際上就是呈現層在運作動畫。那麼。當呈現層運作完動畫是否要講目前屬性的值覆寫會圖層。這樣的行為就稱為fill mode,這個由開發人員決定:

  • kCAFillModeForwards:(保持結束後的值)
  • kCAFillModebackwards:(保持結束前的值)
  • kCAFillModeBoth:(包含以上兩種情況)
  • kCAFillModeRemoved:(預設。當不在播放動畫時,則顯示回圖層的屬性值)

4、全局時間與本地時間

對​

​CALayer​

​或者​

​CAGroupAnimation​

​調整​

​duration​

​和​

​repeatCount​

​/​

​repeatDuration​

​屬性并不會影響到子動畫。可是​

​beginTime​

​。​

​timeOffset​

​speed​

​屬性将會影響到子動畫。

每一個​

​CALayer​

​CAAnimation​

​執行個體都有自己本地時間的概念。是依據父圖層/動畫層級關系中的​

​beginTime​

​timeOffset​

​speed​

​屬性計算。

CoreAnimation有一個全局時間的概念。也就是所謂的馬赫時間(“馬赫”實際上是iOS和Mac OS系統核心的命名)。

用​

​CACurrentMediaTime​

​函數來訪問馬赫時間:

​CFTimeInterval time = CACurrentMediaTime();​

該值傳回的是一個相對值,與現實的時間無關。但能夠通過它來比對不同動畫之間的時間差,iOS提供下面方法來進行不同圖層之間本地時間的轉化:

​- (CFTimeInterval)convertTime:(CFTimeInterval)t fromLayer:(CALayer *)l; ​

- (CFTimeInterval)convertTime:(CFTimeInterval)t toLayer:(CALayer *)l;

通過以上知識能夠實作同步不同圖層的speed,timeOffset、beginTime的動畫。

5、暫停、倒回和快進的實作

設定動畫的​

​speed​

​屬性為0能夠暫停動畫。但不能再加入後再改動。否則會報錯。

但我們能夠通過下面的設定來實作一些調試:

​self.window.layer.speed = 100;​

6、手動動畫

将speed設定為0讓動畫停止播放。然後改動timeOffset來切換不時間的動畫序列。進而實作手動切花動畫的效果。

Easing(緩沖)——讓動畫更加平滑自然

1、CALayer、Animation的緩沖動畫與CAMediaTimingFucntion

首先須要設定​

​CAAnimation​

​的​

​timingFunction​

​屬性,是​

​CAMediaTimingFunction​

​類的一個對象。假設想改變隐式動畫的計時函數,相同也能夠使用​

​CATransaction​

​+setAnimationTimingFunction:​

​方法。來實作緩沖函數。當中有下面預設的緩沖函數:

kCAMediaTimingFunctionLinear            //線性

kCAMediaTimingFunctionEaseIn            //緩進

kCAMediaTimingFunctionEaseOut           //緩出

kCAMediaTimingFunctionEaseInEaseOut     //緩進緩出

​kCAMediaTimingFunctionDefault           //預設的效果與​

​kCAMediaTimingFunctionEaseInEaseOut類似,但效果更佳不明顯

2、UIView的緩沖動畫

通過設定UIView的options參數加入例如以下常量也能夠實作緩沖動畫的效果:

​UIViewAnimationOptionCurveEaseInOut  UIViewAnimationOptionCurveEaseIn  UIViewAnimationOptionCurveEaseOut  UIViewAnimationOptionCurveLinear​

3、緩沖和關鍵幀動畫

​CAKeyframeAnimation​

​有一個​

​NSArray​

​類型的​

​timingFunctions​

​屬性。我們能夠用它來對每次動畫的步驟指定不同的計時函數。可是指定函數的個數一定要等于​

​keyframes​

​數組的元素個數減一,由于它是描寫叙述每一幀之間動畫速度的函數。

4、自己定義緩沖函數

臨時不讨論。

Timer-Based Animation(基于定時器的動畫)——我們能夠通過事務來實作動畫。設定關鍵幀,讓中間的過渡自己主動計算得出。也能夠基于定時器來設定每個繪制周期的變換來實作動畫。

iOS提供一下兩種形式來實作基于定時器的動畫:

  • NSTimer  :并非依據實際幀率來運作,是以CADispaly是更好的解決方式
  • CADispaly  :依據實際的幀率來運作。更加适合

但不管是NSTimer還是CADispaly本質上都是基于runloop,NSTImer把每一個時間觸發的事件注冊到runloop裡面。以待制定。

而CADisplay則把任務直接嵌套進繪制操作之前。

Core Animation 之 性能優化

1、CPU &  GPU

CPU(中央處理器)和GPU(圖形處理器)都是能用來處理。

總的來說。我們能夠用軟體(使用CPU)做不論什麼事情,可是對于圖像處理,通經常使用硬體會更快,由于GPU使用圖像對高度并行浮點運算做了優化。

由于某些原因,我們想盡可能把螢幕渲染的工作交給硬體去處理。問題在于GPU并沒有無限制處理性能。并且一旦資源用完的話,性能就會開始下降了(即使CPU并沒有全然占用)。

性能優化的本質就會合理地利用CPU與GPU,使他們不會超出負荷。

Core Animation處于iOS的核心地位,不管是應用内還是應用外都會用到它。是以iOS特别設計了一個程序來運作渲染相關的任務,也叫渲染服務。渲染服務管理動畫和螢幕上組合的圖層。

當執行一段動畫的時候。這個過程會被切分為六個階段,包含應用内的四個階段,與應用外的2個階段。當中應用内的階段例如以下:

  • 布局(CPU):這是準備你的視圖/圖層的層級關系。以及設定圖層屬性(位置,背景色。邊框等等)的階段。
  • 顯示(CPU):這是圖層的寄宿圖檔被繪制的階段。繪制有可能涉及你的-drawRect:

    和-drawLayer:inContext:

    方法的調用路徑。

  • 準備(CPU):這是Core Animation準備發送動畫資料到渲染服務的階段。這同一時候也是Core Animation将要運作一些别的事務比如解碼動畫過程中将要顯示的圖檔的時間點。
  • 送出(CPU):這是最後的階段,Core Animation打包全部圖層和動畫屬性,然後通過IPC(内部處理通信)發送到渲染服務進行顯示。

當資料被打包到渲染服務程序。會将其反序列化形成還有一個渲染樹。

使用這個渲染樹對動畫的每一幀做出例如以下工作:

  • 生成渲染樹:(CPU)對全部的圖層屬性計算中間值。設定OpenGL幾何形狀(紋理化的三角形)來運作渲染
  • 渲染(GPU):在螢幕上渲染可見的三角形
減少GPU圖層繪制的部分場景:
  • 太多的幾何結構 - 這發生在須要太多的三角闆來做變換,以應對處理器的栅格化的時候。現代iOS裝置的圖形晶片能夠處理幾百萬個三角闆。是以在Core Animation中幾何結構并非GPU的瓶頸所在。但因為圖層在顯示之前通過IPC發送到渲染server的時候(圖層實際上是由非常多小物體組成的特别重量級的對象),太多的圖層就會引起CPU的瓶頸。這就限制了一次展示的圖層個數(見本章興許“CPU相關操作”)。
  • 重繪 - 主要由重疊的半透明圖層引起。GPU的填充比率(用顔色填充像素的比率)是有限的,是以須要避免重繪(每一幀用相同的像素填充多次)的發生。在現代iOS裝置上,GPU都會應對重繪;即使是iPhone 3GS都能夠處理高達2.5的重繪比率。并任然保持60幀率的渲染(這意味着你能夠繪制一個半的整屏的備援資訊,而不影響性能),而且新裝置能夠處理很多其它。
  • 離屏繪制 - 這發生在當不能直接在螢幕上繪制。而且必須繪制到離屏圖檔的上下文中的時候。離屏繪制發生在基于CPU或者是GPU的渲染,或者是為離屏圖檔配置設定額外記憶體,以及切換繪制上下文,這些都會減少GPU性能。對于特定圖層效果的使用,比方圓角,圖層遮罩。陰影或者是圖層光栅化都會強制Core Animation提前渲染圖層的離屏繪制。

    但這不意味着你須要避免使用這些效果,僅僅是要明确這會帶來性能的負面影響。

  • 過大的圖檔 - 假設視圖繪制超出GPU支援的2048x2048或者4096x4096尺寸的紋理,就必須要用CPU在圖層每次顯示之前對圖檔預處理,相同也會減少性能。
減少CPU圖層繪制的部分場景:
  • 布局計算 - 假設你的視圖層級過于複雜,當視圖呈現或者改動的時候,計算圖層幀率就會消耗一部分時間。特别是使用iOS6的自己主動布局機制尤為明顯。它應該是比老版的自己主動調整邏輯加強了CPU的工作。
  • 視圖惰性載入 - iOS僅僅會當視圖控制器的視圖顯示到螢幕上時才會載入它。這對記憶體使用和程式啟動時間非常有優點,可是當呈現到螢幕上之前,按下button導緻的很多工作都會不能被及時響應。比方控制器從資料庫中擷取資料,或者視圖從一個nib檔案裡載入,或者涉及IO的圖檔顯示(見興許“IO相關操作”)。都會比CPU正常操作慢得多。
  • Core Graphics繪制 - 假設對視圖實作了-drawRect:

    方法,或者CALayerDelegate

    的-drawLayer:inContext:

    方法,那麼在繪制不論什麼東西之前都會産生一個巨大的性能開銷。為了支援對圖層内容的随意繪制,Core Animation必須建立一個記憶體中等大小的寄宿圖檔。然後一旦繪制結束之後,必須把圖檔資料通過IPC傳到渲染server。在此基礎上,Core Graphics繪制就會變得十分緩慢。是以在一個對性能十分挑剔的場景下這樣做十分不好。

  • 解壓圖檔 - PNG或者JPEG壓縮之後的圖檔檔案會比同品質的位圖小得多。可是在圖檔繪制到螢幕上之前,必須把它擴充成完整的未解壓的尺寸(通常等同于圖檔寬 x 長 x 4個位元組)。為了節省記憶體。iOS通常直到真正繪制的時候才去解碼圖檔(14章“圖檔IO”會更具體讨論)。

    依據你載入圖檔的方式,第一次對圖層内容指派的時候(直接或者間接使用

    UIImageView

    )或者把它繪制到Core Graphics中。都須要對它解壓。這種話,對于一個較大的圖檔,都會占用一定的時間。
2、Instruments實作App性能優化,操作順序通常例如以下:
  • 加入優化工具
  • 選擇福選項。設定感興趣的資料
  • 對照測試得結果

1、軟體繪制

軟體畫圖意為不借助GPU的圖形繪制。在iOS中通常就是由Core Graphics來實作。但其對照Core Animation和OpenGL,Core Graphics要慢不少,并且也十分消耗記憶體。

軟體畫圖不僅效率低,還會消耗可觀的記憶體。​

​CALayer​

​僅僅須要一些與自己相關的記憶體:僅僅有它的寄宿圖會消耗一定的記憶體空間。即使直接賦給​

​contents​

​屬性一張圖檔,也不須要添加額外的照片存儲大小。假設同樣的一張圖檔被多個圖層作為​

​contents​

​屬性,那麼他們将會共用同一塊記憶體,而不是複制記憶體塊。

可是一旦你實作了​

​CALayerDelegate​

​協定中的​

​-drawLayer:inContext:​

​方法或者​

​UIView​

​中的​

​-drawRect:​

​方法(事實上就是前者的包裝方法),圖層就建立了一個繪制上下文,這個上下文須要的大小的記憶體可從這個算式得出:圖層寬*圖層高*4位元組。寬高的機關均為像素。對于一個在Retina iPad上的全屏圖層來說。這個記憶體量就是 2048*1526*4位元組,相當于12MB記憶體,圖層每次重繪的時候都須要又一次抹掉記憶體然後又一次配置設定。

軟體畫圖的代價昂貴,除非絕對必要。你應該避免重繪你的視圖。

提高繪制性能的秘訣就在于盡量避免去繪制。

2、矢量圖形

我們用Core Graphics來畫圖的一個通常原因就是僅僅是用圖檔或是圖層效果不能輕易地繪制出矢量圖形。矢量畫圖包括一下這些:

  • 随意多邊形(不不過一個矩形)
  • 斜線或曲線
  • 文本
  • 漸變
文章中實作了例如以下效果的demo:
Core Animation學習總結

事實上現思路就是每當有touch event發生,則向UIBezierPath中加入一條直線。但在對于螢幕中每當有一個touch event事件發生,意味着整個螢幕都要又一次繪制一遍,當須要又一次繪制的内容越來越多,則會引起幀率的下降。

這時候我們能夠通過髒矩陣來對這個問題進行優化。

3、髒矩形

髒矩形是一個能制定又一次繪制區域的機制。

在程式中則是通過用setNeedDispalyInRect來替代setNeedDispaly方法來實作繪制詳細的區域,詳細實作見文章。

4、異步繪制

UIKit的單線程天性意味着寄宿圖通常要在主線程上更新,這意味着繪制會打斷使用者互動,甚至讓整個app看起來處于無響應狀态。我們對此無能為力,可是假設能避免使用者等待繪制完畢就好多了。

針對這個問題,core Animation提供了一下兩種方案來實作異步繪制,提高界面的響應效率:

  • CATiledLayer(詳細實作可見第六章)
  • drawsAsynchronously(????)

Image IO(圖像IO)——研究怎樣優化從閃存或者網絡中載入和顯示圖檔

1、載入與潛伏

畫圖實際消耗的時間通常并非影響性能的因素,并且若把圖檔直接存儲在記憶體,會損耗大量的資源,是以須要在應用執行的時候周期性地載入和解除安裝圖檔。

圖檔檔案的載入速度同一時候受到CPU及IO(輸入/輸出)延遲的影響。

iOS裝置中的閃存已經比傳統硬碟快非常多了。但仍然比RAM慢将近200倍左右,這就須要慎重地管理載入。以避免延遲。

有時候圖檔也須要從遠端網絡連接配接中下載下傳,這将會比從磁盤載入要消耗很多其它的時間,甚至可能因為連接配接問題而載入失敗(在幾秒鐘嘗試之後)。你不能在主線程中載入網絡,并在螢幕當機期間期望使用者去等待它。是以須要背景線程。

2、異步線程載入

因為圖檔的載入是十分耗時間的,若把該操作放置在主線程中運作會減少CPU的使用率甚至拖慢幀率。能夠通過GCD或者NSOperationQueue來實作異步載入最後再在主線程中同步發起渲染就可以。

3、延遲解壓

一旦圖檔檔案被載入使用。就必需要經過解碼(解壓)的過程,解碼過程是一個相當複雜的任務。耗時長也占大量的記憶體。

對于PNG:載入相對長。檔案相對更大,但解碼比較快。

對于JPEG:載入快,圖檔小,但解碼算法複雜耗時長。

因為iOS系統會讓載入完畢的圖檔不會馬上解壓,而是到須要用的時刻才正式解壓。是以會影響性能。

  • iOS系統提供下面三種方式來實作繞過延遲解壓的機制
  • imageName方法是能避免延遲載入。并且該方法在載入後會馬上解壓,但僅僅相應用資源束有效。
  • 将載入圖檔設定為圖層内容。如UIImageView的iamge屬性。但這須要在主線程運作。是以不會對性能有大的提升
  • 使用ImageIO架構

4、使用CATiledLayer實作異步載入和顯示大型圖檔

5、分辨率交換

6、使用imageNamed實作緩存

imageName方法是能避免延遲載入,并且該方法在載入後會馬上解壓,但僅僅相應用資源束有效。是以網絡圖檔無效。

之前我們提到使用​

​[UIImage imageNamed:]​

​載入圖檔有個優點在于能夠立馬解壓圖檔而不用等到繪制的時候。可是​

​[UIImage imageNamed:]​

​方法有還有一個很顯著的優點:它在記憶體中自己主動緩存了解壓後的圖檔。即使你自己沒有保留對它的不論什麼引用。

是以也要注意不能用于載入大圖檔,不然會占用大量的記憶體資源。

  • 對于下面場景不能使用imageName。須要自己實作緩存機制:
  • [UIImage imageNamed:]

    方法隻适用于在應用程式資源束檔案夾下的圖檔,可是大多數應用的很多圖檔都要從網絡或者是使用者的相機中擷取,是以

    [UIImage imageNamed:]

    就沒法用了。
  • [UIImage imageNamed:]

    緩存用來存儲應用界面的圖檔(button,背景等等)。假設對比片這樣的大圖也用這樣的緩存,那麼iOS系統就非常可能會移除這些圖檔來節省記憶體。那麼在切換頁面時性能就會下降,由于這些圖檔都須要又一次載入。對傳送器的圖檔使用一個單獨的緩存機制就行把它和應用圖檔的生命周期解耦。

  • 緩存機制并非公開的。是以你不能非常好地控制它。比如,你沒法做到檢測圖檔是否在載入之前就做了緩存。不可以設定緩存大小,當圖檔無用的時候也不能把它從緩存中移除。
7、自己定義緩存
  • 若須要實作自己的緩存機制。通常得從下面四個方面進行考慮:
  • 選擇一個合适的緩存鍵 - 緩存鍵用來做圖檔的唯一辨別。假設實時建立圖檔,通常不太好生成一個字元串來區分别的圖檔。

    在我們的圖檔傳送帶樣例中就非常easy,我們能夠用圖檔的檔案名稱或者表格索引。

  • 提前緩存 - 假設生成和載入資料的代價非常大。你可能想當第一次須要用到的時候再去載入和緩存。提前載入的邏輯是應用内在就有的。可是在我們的樣例中,這也非常好實作,由于對于一個給定的位置和滾動方向。我們就能夠精确地推斷出哪一張圖檔将會出現。
  • 緩存失效 - 假設圖檔檔案發生了變化。如何才幹通知到緩存更新呢?這是個非常困難的問題(就像菲爾 卡爾頓提到的),可是幸運的是當從程式資源載入靜态圖檔的時候并不須要考慮這些。對使用者提供的圖檔來說(可能會被改動或者覆寫),一個比較好的方式就是當圖檔緩存的時候打上一個時間戳以便當檔案更新的時候作比較。
  • 緩存回收 - 當記憶體不夠的時候,如何推斷哪些緩存須要清空呢?這就須要到你寫一個合适的算法了。幸運的是,對緩存回收的問題。蘋果提供了一個叫做

    NSCache

    通用的解決方式

8、NSCache

NSCache和NSDictionary類似。都是直接通過鍵值進行訪問,但不同的是,NSCache所持有的對象在記憶體不足的時候。會自己主動将其釋放。

  • 當然開發人員能夠通過下面設定來粗顆粒度地進行緩存管理的限制
  • -setCountLimit:

    方法設定緩存大小

  • -setObject:forKey:cost:

    來對每一個存儲的對象指定消耗的值來提供一些暗示

  • -setTotalCostLimit:

    方法來指定全體緩存的尺寸

9、檔案格式與載入性能
1、隐形繪制
  • 寄宿層能夠通過下面方式顯示繪制
  • Core Graphics
  • 給contents屬性指派圖檔
  • 在螢幕外事先繪制CGContext
  • 當發生下面場景會觸發隐式繪制
  • 使用特性的圖層屬性
  • 特定的視圖
  • 特定視圖的子類

2、文本

CATextLayer與UILable都是直接将文本繪制在圖層的寄宿層内,是以要避免頻繁的修改,若該文本須要頻繁修改,能夠先将其放在一個子圖層上,通過contentMode來等比例縮放寄宿層。

3、光栅化

我們提到了​

​CALayer​

​shouldRasterize​

​屬性(光栅化)。它能夠解決重疊透明圖層的混合失靈問題。

啟用​

​shouldRasterize​

​屬性會将圖層繪制到一個螢幕之外的圖像。然後這個圖像将會被緩存起來并繪制到實際圖層的​

​contents​

​和子圖層。

假設有非常多的子圖層或者有複雜的效果應用,這樣做就會比重繪全部事務的全部幀劃得來得多。

可是光栅化原始圖像須要時間。并且還會消耗額外的記憶體。

當我們使用得當時,光栅化能夠提供非常大的性能優勢(如你在第12章所見),可是一定要避免作用在内容不斷變動的圖層上,否則它緩存方面的優點就會消失。并且會讓性能變的更糟。

為了檢測你是否正确地使用了光栅化方式,用Instrument檢視一下Color Hits Green和Misses Red項目。是否已光栅化圖像被頻繁地重新整理(這樣就說明圖層并非光栅化的好選擇,或則你無意間觸發了不必要的改變導緻了重繪行為)。

總結:會占用較多記憶體,要避免反複繪制。是以一旦應用要盡量降低又一次繪制,而多利用快照緩存。

4、離屏渲染

  • 當圖層的下面屬性被改動會觸發離屏渲染
  • 圓角(當和maskToBounds

    一起使用時)

  • masks(圖層蒙闆)
  • shadows(陰影)
  • shouldRasterize(光栅化)
  • edge antialiasing(抗鋸齒)
  • group opacity(不透明)

螢幕外渲染和我們啟用光栅化時相似。除了它并沒有像光栅化圖層那麼消耗大。子圖層并沒有被影響到,并且結果也沒有被緩存,是以不會有長期的記憶體占用。可是,假設太多圖層在螢幕外渲染依舊會影響到性能

對于那些須要動畫并且要在螢幕外渲染的圖層來說。你能夠用​

​CAShapeLayer​

​,​

​contentsCenter​

​shadowPath​

​來獲得相同的表現并且較少地影響到性能。

5、混合和過度繪制

開發人員應該盡量降低重疊圖層的反複渲染,由于對于使用者看來某些遮擋的圖層的内容是無關緊要的,但渲染就會消耗資源。是以不管不論什麼場景都建議例如以下操作:

  • 給視圖的backgroundColor

    屬性設定一個固定的,不透明的顔色

  • 設定opaque

    屬性為YES

  • 明智地使用shouldRasterize

    屬性,能夠将一個固定的圖層體系折疊成單張圖檔,這樣就不須要每一幀又一次合成了,也就不會有由于子圖層之間的混合和過度繪制的性能問題了。

當然光栅化是是詳細場景二選擇使用,不然也會引入别的性能問題,如占用大量記憶體。

6、降低圖層數量

初始化圖層,處理圖層,打包通過IPC發給渲染引擎,轉化成OpenGL幾何圖形,這些是一個圖層的大緻資源開銷。其實,一次性可以在螢幕上顯示的最大圖層數量也是有限的。

确切的限制數量取決于iOS裝置。圖層類型。圖層内容和屬性等。

可是總得說來能夠容納上百或上千個,以下我們将示範即使圖層本身并沒有做什麼也會遇到的性能問題。

7、對象回收

處理巨大數量的相似視圖或圖層時另一個技巧就是回收他們。對象回收在iOS頗為常見。​

​UITableView​

​UICollectionView​

​都實用到,​

​MKMapView​

​中的動畫pin碼也實用到,還有其它非常多樣例。

Q&A:

  • Q:圖層沒有寄宿層,是否等于無法顯示内容?(寄宿層)
  • A:不是,還有通過矢量圖繪制的方式來實作圖形呈現。如通用的如今應該就是通過算來來繪制矢量圖的,僅僅有須要顯示圖檔或者調用core graphics的時候才會生成寄宿層。是以若非必要不要實作draw方法。不然系統會預設加入一個寄宿層。
  • Q:組透明的點顔色計算公式?(視覺效果)
  • A:若某子view是透明的。那麼它的顔色公式為:child_color*alpha + super_color*(1-alpha)。
  • Q:3D效果與共享滅點的詳細操作?(變換)
  • A:在做3D效果時要盡量将全部圖形的滅點設定在螢幕的中心。是以建議先在螢幕的中心建立圖像。然後通過transform的形式來移動圖層。那麼就能保證滅點在螢幕中心。
  • Q:3D變化計算?(變換)
  • A:提供了平移、旋轉、縮放,但每次操作都是基于二維的,是以注意目前的參考坐标系,剩下的計算與二維一樣。
  • Q:立方體的光亮與陰影原理?(變換)
  • A:通過GLK庫的函數計算垂直,并加入陰影層。
  • Q:3D點選事件處理?(變換)
  • A:在3D圖層中。由于一個點選的點,實際上可能會穿過兩個圖層的點,這時事件攔截的順序由subviews數組的順序認為,也就是誰最靠近使用者視覺,誰有限響應。
  • Q:正常的界面繪制是通過矢量繪制還是寄宿圖繪制實作?(專用圖層)
  • A:正常界面是矢量繪制完畢的。
  • Q:平面化3d層級結構的意思?(專用圖層)
  • A:
  • Q:CATiledLayer解決大圖載入(專用圖層)