檔案夾:
- The Layer Beneath
- The Layer Tree(圖層樹)
- The Backing Image(寄宿層)
- Layer Geometry(圖層幾何學)
- Visual Effects(視覺效果)
- Transforms(變換)
- Specialized Layers(專有圖層)
- Setting Things in Motion
- Implicit Animations(隐式動畫)
- Explicit Animations(顯式動畫)
- Layer Time(圖層時間)
- Easing(緩沖)
- Timer-Based Animation(基于定時器的動畫)
- The Performance of a Lifetime
- Tuning for Speed(性能調優)
- Efficient Drawing(高效畫圖)
- Image IO(圖像IO)
- Layer Performance(圖層性能)
Core Animation 之 CALayer
1、圖層與視圖的差别:
是以以上四層。每一層都負責不同的任務,其資料流是視圖-》圖層-》呈現樹-》渲染樹。 而且繪制周期60FPS也是會随着系統的狀态而變化的,若系統資源超載,而會通過降低繪制次數來確定系統能穩定執行。 3、視圖動畫 視圖動畫是顯式,由于UIView預設把CALayer的隐式動畫禁止掉了。是以要通過動畫Block的形式才幹取消動畫的限制。(動畫block實際上就是曾經的動畫棧)。 而且視圖能實作的動畫僅僅是圖層所開放的一部分,都是2D動畫,是以視圖動畫的效果會稍稍簡單。 4、圖層動畫 圖層動畫是隐性動畫。僅僅要改動圖層的屬性。其變化都會以預設的漸變形式呈現出來(詳細原理見《隐式動畫》)。而且圖層動畫支援很多其它視圖動畫無法實作的效果。如:
5、更适宜使用CAlayer呈現内容的場景 由于UIView與CALayer都能夠呈現内容。盡管CALayer不能直接實作事件響應。但開發人員也能夠通過hit-test機制的原理來自己實作事件響應,那什麼場景更加适合用CALayer而不是UIView呢?例如以下所看到的:
|
1、寄宿層&Contents屬性 CALayer有一個名曰Contents的屬性,這個屬性是與寄宿層相相應了,而contents屬性指向的對象必須為CGImageRef類型(一個指向CGImage結構的指針),是以寄宿層是用來展示圖檔所用的。例如以下情況會調用寄宿層:
core Graphics能夠實作自己定義繪制,但通常不建議那麼做,由于core Graphics繪制會預設生成一個繪制專用的存儲空間,而這空間有十多M那麼多。會占用大量記憶體,是以Apple不建議實作空的core Graphics更不建議在core Graphics實作不屬于該方法的代碼。 2、contentGravity屬性 與UIView的contentMode屬性相相應,用于調整圖檔的布局,支援一下常量值:
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下的三種坐标系統機關:
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的數值是會事實變動的,例如以下圖: ![]() 2、錨點 錨點屬性是用來指定圖層相對于父圖層的位置。也能夠了解為利用圖層的句柄。默覺得圖層的中心但也能夠改動。在圖層中改動了錨點會産生移動(隐性動畫),相同的錨點也是一個相對值。 例如以下。為錨點的實驗效果圖: 圖一:時分秒針直接以圖層的中點為錨點,由于旋轉時也以其為中心,效果例如以下: 3、坐标系 由于每一個圖層都有自己的坐标系,是以CALayer也提供了一系列的方法用于一個點在不同的坐标系之間轉換,這些方法特别适合于子圖層與父圖層之間的坐标轉換。 事實上UIView與CALayer都有zPosition。但因為UIView隻支援2D變換,是以UIView的zPosition隻适合于用來作圖層的調整,但更加建議用UIView提供的視圖數組管理方法來調整視圖的繪制順序來調整。而CALayer的zPosition是一個重要的三維坐标系。 4、Hit Testing Hit Testing是iOS中一個十分重要的機制,用于檢索點選了的目标圖示,與響應鍊條互相搭配的話。就會将終于目标圖示設定為第一響應者。Hit Testing提供了兩個核心的方法:
5、自己主動布局 對于UIView。通過UIView暴露出來的UIViewAutoresizingMask和NSLayoutConstraint來實作自己主動布局。 但對于CALayer,則須要手動來操作實作,當中最為簡單的方法就是實作CALayerDelegate的例如以下函數: - (void)layoutSublayersOfLayer:(CALayer *)layer; 在該方法内依據目前layer的屬性來計算調整來實作自己主動布局。 由于CALayer實作自己主動布局不友善,是以這也是為什麼更加建議使用UIView來實作界面的建構。 |
Visual Effects(視覺效果)——本節探讨可以通過CALayer實作的附加視覺效果 1、圓角 CALayer有一個叫做cornerRadius的屬性控制圖層角的曲率,這個曲率僅僅影響背景顔色而不影響圖檔或者子圖檔。圓角的計算原理就是一個以CALayer的中點,曲率所設的半徑的原與矩形的交集就是目标圖形。 另一個名曰maskToBounds屬性,就是實作将圖層裡面邊界外的圖形所有分割丢棄。 是以通過cornerRadius+maskToBounds組合能夠實作圓角,但同一時候會引發離屏渲染,若是小量的離屏渲染還好,但如卷軸框的場景,開會有大量的離屏渲染的任務産生,就會嚴重影響性能,這一點也是注意優化的。詳細效果例如以下圖所看到的: 2、圖層邊框 通過設定CALayer的borderWidth與borderColor兩個屬性能夠改動邊框的效果。 效果例如以下: 3、陰影 陰影是一種能達到圖層深度暗示效果的裝飾。 CALayer提供下面參數來定制陰影的效果:
有一點須要注意的,就是陰影的繪制是屬于離屏繪制。是比較效果資源的。是以一定要降低同一螢幕進行大量陰影繪制的情況。 4、陰影裁剪 圖層的陰影很多其它是繼承于内容的外形,而不是依據邊界和角半徑來确定。為了計算出陰影的形狀。core animation會将寄宿層也考慮在内。 但若直接maskToBounds來裁剪,會把陰影效果也裁減掉。 為了解決以上問題。能夠通過專門引入一個陰影圖層來解決,詳細效果例如以下: 圖一:直接maskToBounds裁剪會把陰影效果一并裁剪掉。 PS:不管是陰影還是圓角裁剪都會引發離屏渲染,大量的該類型的圖形須要渲染的話。會減低幀率。 5、shadowPath 屬性 陰影并一定是方形的。我們也能夠通過shadowPath來定制自己想要的陰影形狀。詳細效果例如以下所看到的: 6、圖層蒙版 通過masksToBounds屬性。我們能夠實作邊界裁剪,但我們還須要更加靈活的裁剪需求的時候就能夠通過圖層蒙版來實作。CALayer提供一個mask的屬性來解決一個問題。而mask本來就是指向還有一個圖層的指針。其詳細原理例如以下圖所看到的: 從上圖效果能夠知道mask舒心僅僅關心形狀的交集,而顔色還是由原來的圖形的顔色決定。 另一點須要注意的是圖層蒙版也會引發離屏渲染,會帶來性能問題,是以使用的時候也得多加注意。 7、拉伸過濾 當我們視圖顯示一個圖檔的時候。都應該以正确的比例,正确的1:1像素顯示在螢幕上。原因例如以下:
但有時候我們就須要縮略圖。所專門另外存儲縮略圖這對記憶體來說。 這時就能夠通過CALayer的minificationFilter(縮小濾波器)和magnificationFilter(方法濾波器)屬性實作圖形的縮放算法。當中提供下面三種預設的縮放算法:
對于大圖的縮放,採用kCAFilterLinear、kCAFilterTrilinear,效果會比較好。 對于小圖、較少斜線的圖的縮放,。採用kCAFilterNearest效果比較好。 圖一:採用kCAFilterLinear的方法濾波器算法的效果。 8、透明組 UIView有一個alpha屬性類确定視圖的透明度。而CALayer有一個與之相應的屬性——opacity。這兩個屬性都會影響到子圖層。例如以下圖所看到的: 當我們将view2的alpha數值設定為0.5,這時候,對于label所處的點的顔色計算公式為:50%label + 25%view + 25%background,是以就是灰色偏白的顔色。 若想整個圖層的色調保持一緻,能夠通過将shouldRasterize屬性設定為YES,那麼圖層及其子圖層将被整合成一個總體的圖檔。效果例如以下: 圖一:shouldRasterize屬性設定為預設值NO的效果。 |
1、仿射變換 UIView相應的transfrom屬性是一個CGAffineTransfrom類型。用于實作二維空間旋轉、平移、縮放、斜切。 而CALayer的transform屬性是一個CATransforms3D。能應用3維空間進行旋轉、平移、縮放、斜切等效果。 當中,仿射變化的數學原理例如以下: 當中有一點須要注意的,就是旋轉的angle是以弧度制為機關的。 iOS系統提供下面方法來實作混合變換,能同一下面的組合函數實作複雜的變形模式: 圖一:建立一個空的變換結構體。 2、3D變化 3D變化與2D變化是十分相似的,不同的僅僅是3D變換是3個次元的,加入了Z軸。其數學原理例如以下: 3、透視投影 在真實的世界中,當物體遠離我們。因為視角的原因,其會變小。是以為了讓3D效果更佳真實,須要引入投影變換,盡管core animation并沒有提供給我們,但十分簡單,其數學實作例如以下: 僅僅要将m34 = -1/d, d= 500~1000,(d越小越失真,d越大透視效果越弱)。 圖3.1:沒實作透視投影的旋轉效果。 4、滅點 在人的視覺中。當物體離人越遠則會變得越小,當接近無窮遠的時候就會彙聚成一個不可見的點,這個點就叫滅點。現實生活中,這個點通常就是中心點,是以在程式中我們也要讓圖形的滅點集中在螢幕的中點,例如以下所看到的: 而實作方式則是。首先加入圖形的時候先以螢幕中點為錨點加入,然後通過transfrom來講圖層移動到恰當的位置。 5、sublayerTransform sublayerTransform是一種将全部對應的配置統一設定到該圖層的全部子圖層的便捷屬性。 6、3D坐标下的圖層背面 在3D坐标下,圖層的背面也是會繪制的,并且是正面的鏡像。 我們能夠通過CALayer的doubleSided屬性來決定是否運作雙面繪制。 7、扁平化圖層 假設父圖層的坐标發生變換,那麼子圖層也會随着父圖層而進行相同的變換,如7.1圖所看到的。但有時我們僅僅想變換父圖層并不想變換子圖層。這時就得做相對變換來抵消掉父圖層的變換。讓視覺效果看起來子圖層是精巧的。例如以下圖所看到的: 圖7.1:2D相對旋轉理論圖 我們能夠看出,在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屬性時自己主動應用的動态稱為行為。一組行為的運作步驟例如以下所看到的:
經過以上的整個流程,要麼actionForKey傳回nil則無動畫效果,要麼就是傳回CAAction,然後CALayer利用它實作動畫。 是以能夠推動出UIView是怎樣禁止隐式動畫的,就是講CALayer的delegate設定為自身。然後在actionForLayer:forKey方法中傳回nil。
4、呈現與模型 在iOS中。螢幕每秒鐘又一次重新整理螢幕60次。 是以Core Animaiton就須要在設定一次新值和新值生效之間,對螢幕上的圖層進行又一次組織。 正是以為上面的機制的存在。是以才會有iOS才會有圖層以及呈現層之間的關系,圖層更像是model,而呈現層就是view,Core Animation就是Controller,是以在一個繪制周期内,圖層負責收集與儲存使用者對屬性的改動,到繪制時刻時。就将圖層的資料覆寫到呈現樹。 我們能夠通過CALayer的 -presentationLayer方法來擷取正在螢幕上顯示的呈現樹的資料,盡管一般不須要。但在下面情況下會比較有作用
|
1、Core Animation的類圖架構
2、基礎屬性動畫 基礎動畫主要由CABasicAnimation實作,由上圖可知道。而CABasicAnimation繼承于CAPropertyAnimation屬性動畫,通過設定下面三個數值以及其它的選項,就可以實作自己主動動畫:
當中toValue與byValue不能同一時候使用,toVaule是絕對值,byValue是相對值。 屬性動畫都是針對關鍵幀的動畫。也就是說僅僅關心出發點與結束點,中間的過渡能夠自己生成也能夠預設。 3、關鍵幀動畫 CAKeyFrameAnimation用于實作關鍵幀動畫,能通過設定其animations數組來定義每一個關鍵幀的位置,也能夠直接通過path屬性來定義運動的路徑。 4、affineTransform屬性 若我們讓一個圖形沿着曲線運動。能夠通過設定affineTransform。讓其能沿着曲線的切線運動進而讓運動更加真實。前後效果圖例如以下圖所看到的: 5、虛拟屬性 屬性動畫實際上是針對關鍵路徑而不是一個鍵的。這就意味着能夠對子屬性甚至虛拟屬性做動畫。 如若我們想實作旋轉的效果,本來我們須要在keyPath上設定“transform”, 若使用虛拟屬性。能夠直接在keyPath上直接設定“transfrom.rotation”,這樣在設定formValue與toValue時就能夠直接設定弧度叫的值。 事實上transfrom.rotation這個屬性是并不存在的,而是core aniamiton自己主動依據CAValueFunction來又一次計算transform的數值所得,正由于如此才稱之為虛拟屬性。 6、動畫組 CAAnimationGroup是一種組合動畫的解決方式。通過CAAnimationGroup加入沿曲線運動與顔色變化的動畫。 7、過渡 略。 8、在動畫的過程中取消動畫 Core Animation提供了一部分的方法來實作動畫加入以及移除。例如以下圖所看到的: |
1、CAMediaTiming協定 CAMediaTiming協定定義了在一段動畫内控制逝去時間的屬性集合。 CALayer和CAAnimaition都實作了該協定,是以時間能夠被随意圖層或者一段動畫的類所控制。 CAMediaTiming協定下定義的一些核心屬性:
能夠通過将repeatCount或者repeatDuration設定為INFINITY來實作動畫無限循環播放。但不能同一時候使用這兩個屬性。 2、相對時間 在Core Animation中,時間是相對的,每一個動畫都有自己的描寫叙述時間,能夠獨立的加速、延遲或者偏移,當中有下面關鍵屬性:
3、fillMode 當一個圖層産生動畫,實際上就是呈現層在運作動畫。那麼。當呈現層運作完動畫是否要講目前屬性的值覆寫會圖層。這樣的行為就稱為fill mode,這個由開發人員決定:
4、全局時間與本地時間 對 或者 調整 和 / 屬性并不會影響到子動畫。可是 。 屬性将會影響到子動畫。 每一個 執行個體都有自己本地時間的概念。是依據父圖層/動畫層級關系中的 屬性計算。 CoreAnimation有一個全局時間的概念。也就是所謂的馬赫時間(“馬赫”實際上是iOS和Mac OS系統核心的命名)。 用 函數來訪問馬赫時間: 該值傳回的是一個相對值,與現實的時間無關。但能夠通過它來比對不同動畫之間的時間差,iOS提供下面方法來進行不同圖層之間本地時間的轉化: - (CFTimeInterval)convertTime:(CFTimeInterval)t toLayer:(CALayer *)l; 通過以上知識能夠實作同步不同圖層的speed,timeOffset、beginTime的動畫。 5、暫停、倒回和快進的實作 設定動畫的 屬性為0能夠暫停動畫。但不能再加入後再改動。否則會報錯。 但我們能夠通過下面的設定來實作一些調試: 6、手動動畫 将speed設定為0讓動畫停止播放。然後改動timeOffset來切換不時間的動畫序列。進而實作手動切花動畫的效果。 |
Easing(緩沖)——讓動畫更加平滑自然 1、CALayer、Animation的緩沖動畫與CAMediaTimingFucntion 首先須要設定 的 屬性,是 類的一個對象。假設想改變隐式動畫的計時函數,相同也能夠使用 方法。來實作緩沖函數。當中有下面預設的緩沖函數: kCAMediaTimingFunctionLinear //線性 kCAMediaTimingFunctionEaseIn //緩進 kCAMediaTimingFunctionEaseOut //緩出 kCAMediaTimingFunctionEaseInEaseOut //緩進緩出 kCAMediaTimingFunctionEaseInEaseOut類似,但效果更佳不明顯 2、UIView的緩沖動畫 通過設定UIView的options參數加入例如以下常量也能夠實作緩沖動畫的效果: 3、緩沖和關鍵幀動畫 有一個 類型的 屬性。我們能夠用它來對每次動畫的步驟指定不同的計時函數。可是指定函數的個數一定要等于 數組的元素個數減一,由于它是描寫叙述每一幀之間動畫速度的函數。 4、自己定義緩沖函數 臨時不讨論。 |
Timer-Based Animation(基于定時器的動畫)——我們能夠通過事務來實作動畫。設定關鍵幀,讓中間的過渡自己主動計算得出。也能夠基于定時器來設定每個繪制周期的變換來實作動畫。 iOS提供一下兩種形式來實作基于定時器的動畫:
但不管是NSTimer還是CADispaly本質上都是基于runloop,NSTImer把每一個時間觸發的事件注冊到runloop裡面。以待制定。 而CADisplay則把任務直接嵌套進繪制操作之前。 |
Core Animation 之 性能優化
1、CPU & GPU CPU(中央處理器)和GPU(圖形處理器)都是能用來處理。 總的來說。我們能夠用軟體(使用CPU)做不論什麼事情,可是對于圖像處理,通經常使用硬體會更快,由于GPU使用圖像對高度并行浮點運算做了優化。 由于某些原因,我們想盡可能把螢幕渲染的工作交給硬體去處理。問題在于GPU并沒有無限制處理性能。并且一旦資源用完的話,性能就會開始下降了(即使CPU并沒有全然占用)。 性能優化的本質就會合理地利用CPU與GPU,使他們不會超出負荷。 Core Animation處于iOS的核心地位,不管是應用内還是應用外都會用到它。是以iOS特别設計了一個程序來運作渲染相關的任務,也叫渲染服務。渲染服務管理動畫和螢幕上組合的圖層。 當執行一段動畫的時候。這個過程會被切分為六個階段,包含應用内的四個階段,與應用外的2個階段。當中應用内的階段例如以下:
當資料被打包到渲染服務程序。會将其反序列化形成還有一個渲染樹。 使用這個渲染樹對動畫的每一幀做出例如以下工作:
|
1、軟體繪制 軟體畫圖意為不借助GPU的圖形繪制。在iOS中通常就是由Core Graphics來實作。但其對照Core Animation和OpenGL,Core Graphics要慢不少,并且也十分消耗記憶體。 軟體畫圖不僅效率低,還會消耗可觀的記憶體。 僅僅須要一些與自己相關的記憶體:僅僅有它的寄宿圖會消耗一定的記憶體空間。即使直接賦給 屬性一張圖檔,也不須要添加額外的照片存儲大小。假設同樣的一張圖檔被多個圖層作為 屬性,那麼他們将會共用同一塊記憶體,而不是複制記憶體塊。 可是一旦你實作了 協定中的 方法或者 中的 方法(事實上就是前者的包裝方法),圖層就建立了一個繪制上下文,這個上下文須要的大小的記憶體可從這個算式得出:圖層寬*圖層高*4位元組。寬高的機關均為像素。對于一個在Retina iPad上的全屏圖層來說。這個記憶體量就是 2048*1526*4位元組,相當于12MB記憶體,圖層每次重繪的時候都須要又一次抹掉記憶體然後又一次配置設定。 軟體畫圖的代價昂貴,除非絕對必要。你應該避免重繪你的視圖。 提高繪制性能的秘訣就在于盡量避免去繪制。 2、矢量圖形 我們用Core Graphics來畫圖的一個通常原因就是僅僅是用圖檔或是圖層效果不能輕易地繪制出矢量圖形。矢量畫圖包括一下這些:
事實上現思路就是每當有touch event發生,則向UIBezierPath中加入一條直線。但在對于螢幕中每當有一個touch event事件發生,意味着整個螢幕都要又一次繪制一遍,當須要又一次繪制的内容越來越多,則會引起幀率的下降。 這時候我們能夠通過髒矩陣來對這個問題進行優化。 3、髒矩形 髒矩形是一個能制定又一次繪制區域的機制。 在程式中則是通過用setNeedDispalyInRect來替代setNeedDispaly方法來實作繪制詳細的區域,詳細實作見文章。 4、異步繪制 UIKit的單線程天性意味着寄宿圖通常要在主線程上更新,這意味着繪制會打斷使用者互動,甚至讓整個app看起來處于無響應狀态。我們對此無能為力,可是假設能避免使用者等待繪制完畢就好多了。 針對這個問題,core Animation提供了一下兩種方案來實作異步繪制,提高界面的響應效率:
|
Image IO(圖像IO)——研究怎樣優化從閃存或者網絡中載入和顯示圖檔 1、載入與潛伏 畫圖實際消耗的時間通常并非影響性能的因素,并且若把圖檔直接存儲在記憶體,會損耗大量的資源,是以須要在應用執行的時候周期性地載入和解除安裝圖檔。 圖檔檔案的載入速度同一時候受到CPU及IO(輸入/輸出)延遲的影響。 iOS裝置中的閃存已經比傳統硬碟快非常多了。但仍然比RAM慢将近200倍左右,這就須要慎重地管理載入。以避免延遲。 有時候圖檔也須要從遠端網絡連接配接中下載下傳,這将會比從磁盤載入要消耗很多其它的時間,甚至可能因為連接配接問題而載入失敗(在幾秒鐘嘗試之後)。你不能在主線程中載入網絡,并在螢幕當機期間期望使用者去等待它。是以須要背景線程。 2、異步線程載入 因為圖檔的載入是十分耗時間的,若把該操作放置在主線程中運作會減少CPU的使用率甚至拖慢幀率。能夠通過GCD或者NSOperationQueue來實作異步載入最後再在主線程中同步發起渲染就可以。 3、延遲解壓 一旦圖檔檔案被載入使用。就必需要經過解碼(解壓)的過程,解碼過程是一個相當複雜的任務。耗時長也占大量的記憶體。 對于PNG:載入相對長。檔案相對更大,但解碼比較快。 對于JPEG:載入快,圖檔小,但解碼算法複雜耗時長。 因為iOS系統會讓載入完畢的圖檔不會馬上解壓,而是到須要用的時刻才正式解壓。是以會影響性能。
4、使用CATiledLayer實作異步載入和顯示大型圖檔 5、分辨率交換 6、使用imageNamed實作緩存 imageName方法是能避免延遲載入,并且該方法在載入後會馬上解壓,但僅僅相應用資源束有效。是以網絡圖檔無效。 之前我們提到使用 載入圖檔有個優點在于能夠立馬解壓圖檔而不用等到繪制的時候。可是 方法有還有一個很顯著的優點:它在記憶體中自己主動緩存了解壓後的圖檔。即使你自己沒有保留對它的不論什麼引用。 是以也要注意不能用于載入大圖檔,不然會占用大量的記憶體資源。
8、NSCache NSCache和NSDictionary類似。都是直接通過鍵值進行訪問,但不同的是,NSCache所持有的對象在記憶體不足的時候。會自己主動将其釋放。
|
1、隐形繪制
2、文本 CATextLayer與UILable都是直接将文本繪制在圖層的寄宿層内,是以要避免頻繁的修改,若該文本須要頻繁修改,能夠先将其放在一個子圖層上,通過contentMode來等比例縮放寄宿層。 3、光栅化 我們提到了 屬性(光栅化)。它能夠解決重疊透明圖層的混合失靈問題。 啟用 屬性會将圖層繪制到一個螢幕之外的圖像。然後這個圖像将會被緩存起來并繪制到實際圖層的 和子圖層。 假設有非常多的子圖層或者有複雜的效果應用,這樣做就會比重繪全部事務的全部幀劃得來得多。 可是光栅化原始圖像須要時間。并且還會消耗額外的記憶體。 當我們使用得當時,光栅化能夠提供非常大的性能優勢(如你在第12章所見),可是一定要避免作用在内容不斷變動的圖層上,否則它緩存方面的優點就會消失。并且會讓性能變的更糟。 為了檢測你是否正确地使用了光栅化方式,用Instrument檢視一下Color Hits Green和Misses Red項目。是否已光栅化圖像被頻繁地重新整理(這樣就說明圖層并非光栅化的好選擇,或則你無意間觸發了不必要的改變導緻了重繪行為)。 總結:會占用較多記憶體,要避免反複繪制。是以一旦應用要盡量降低又一次繪制,而多利用快照緩存。 4、離屏渲染
螢幕外渲染和我們啟用光栅化時相似。除了它并沒有像光栅化圖層那麼消耗大。子圖層并沒有被影響到,并且結果也沒有被緩存,是以不會有長期的記憶體占用。可是,假設太多圖層在螢幕外渲染依舊會影響到性能 對于那些須要動畫并且要在螢幕外渲染的圖層來說。你能夠用 , 來獲得相同的表現并且較少地影響到性能。 5、混合和過度繪制 開發人員應該盡量降低重疊圖層的反複渲染,由于對于使用者看來某些遮擋的圖層的内容是無關緊要的,但渲染就會消耗資源。是以不管不論什麼場景都建議例如以下操作:
當然光栅化是是詳細場景二選擇使用,不然也會引入别的性能問題,如占用大量記憶體。 6、降低圖層數量 初始化圖層,處理圖層,打包通過IPC發給渲染引擎,轉化成OpenGL幾何圖形,這些是一個圖層的大緻資源開銷。其實,一次性可以在螢幕上顯示的最大圖層數量也是有限的。 确切的限制數量取決于iOS裝置。圖層類型。圖層内容和屬性等。 可是總得說來能夠容納上百或上千個,以下我們将示範即使圖層本身并沒有做什麼也會遇到的性能問題。 7、對象回收 處理巨大數量的相似視圖或圖層時另一個技巧就是回收他們。對象回收在iOS頗為常見。 都實用到, 中的動畫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解決大圖載入(專用圖層)