iOS核心動(dòng)畫高級(jí)技巧:第一部分-圖層

本文是要點(diǎn)型筆記,建議先閱讀以下參考內(nèi)容后再閱讀,完成知識(shí)體系的構(gòu)建:
 [1] View Programming Guide for iOS
 [2] Core Animation Programming Guide
 [3] ios核心動(dòng)畫高級(jí)技巧
 [4] 通過實(shí)現(xiàn)一個(gè)TableView來理解IOS UI編程
 [5] 詳解 CALayer 和 UIView 的區(qū)別和聯(lián)系
 [6] iOS繪圖教程
 [7] Quartz 2D編程指南之一~十三 - 南峰子


LayerKit => Core Animation是一個(gè)復(fù)合引擎,它的職責(zé)就是盡可能快地組合屏幕上不同的可視內(nèi)容咽笼,可視內(nèi)容(圖片、文本、背景色抚官、…)被分解成獨(dú)立的圖層,存儲(chǔ)在一個(gè)叫做【圖層樹】的體系之中阶捆。

圖層可以通過【寄宿圖】來提供可視內(nèi)容凌节,通過【圖層幾何學(xué)/布局特性】鎖定擺放的位置,可以加一些基礎(chǔ)【視覺效果】(圓角洒试、邊框倍奢、陰影、蒙版垒棋、拉伸卒煞、透明…)或高級(jí)視覺效果-【變換】(仿射、3D)叼架;除了圖片和背景純色之外畔裕,CA還提供了一系列【專有圖層】對(duì)繪制能力進(jìn)行了擴(kuò)展衣撬,針對(duì)特殊場(chǎng)景進(jìn)行了封裝和性能優(yōu)化。

注:優(yōu)先級(jí)-displayLayer: > -drawInContext: > -drawLayer:inContext: > -drawRect:

附 UIKit & Quarts 2D:


第一章:圖層的樹狀結(jié)構(gòu)

1. 四個(gè)平行的層級(jí)關(guān)系

視圖樹 —— UIView扮饶,著重于交互-響應(yīng)事件(觸摸/手勢(shì)…)具练,作為CALayer的管理者
模型樹/邏輯樹(目標(biāo)幀) —— CALayer - modelLayer(),不涉及響應(yīng)鏈(通過視圖層級(jí)關(guān)系傳遞觸摸事件的機(jī)制)
呈現(xiàn)樹/動(dòng)畫樹(當(dāng)前幀) —— presentationLayer(), 動(dòng)畫過程中的當(dāng)前值甜无,詳見第七章
渲染樹/顯示樹(下一幀) —— 圖層和動(dòng)畫打包提交到渲染服務(wù)后反序列化所得樹扛点,被用于生成gl三角形s,詳見第十二章

2. CALayer和UIView的區(qū)別和聯(lián)系

  • 兩者通過UIView的layerClass類方法layer屬性聯(lián)系在一起
  • 屬性封裝 - Layer 的 frame 是由 anchorPoint,position,bounds和 transform 共同決定的岂丘,而View 只是簡(jiǎn)單的返回 Layer的 frame(bounds和center/position類似)
  • 分工 - UIView側(cè)重對(duì)顯示內(nèi)容的管理陵究,而CALayer側(cè)重顯示內(nèi)容的繪制(drawXxx())和顯示(display())
  • 事件響應(yīng) - UIResponder決定了UIView能接受并響應(yīng)事件,而CALayer不可以(即使有Hit Testing方法)
  • 隱式動(dòng)畫 - 非根CALayer 支持隱式動(dòng)畫奥帘,而UIView 作為 Layer 的默認(rèn)代理铜邮,通過在actionForLayer:forKey:返回nil默認(rèn)禁止了隱式動(dòng)畫(在animation block中會(huì)自動(dòng)重新啟用,本質(zhì):[CATransaction setDisableActions:NO];)
  • 視圖未暴露的CALayer的功能:
    • 錨點(diǎn)翩概、陰影,圓角,邊框牲距、透明遮罩
    • 非矩形范圍(mask or shadowPath?钥庇?牍鞠?)
    • 3D變換(UIView的transform; CALayer的transformaffineTransform
    • 多級(jí)非線性動(dòng)畫(UIView的默認(rèn)顯式動(dòng)畫都是線性動(dòng)畫)

3. CALayer和UIView的選擇

UIView的適用場(chǎng)景

  • 優(yōu)先使用,原因:自動(dòng)排版/布局和事件處理

CALayer的適用場(chǎng)景:

  • 可以在Mac OS上運(yùn)行的跨平臺(tái)應(yīng)用
  • 使用多種CALayer的子類(見第六章)评姨,并且不想創(chuàng)建額外的UIView去包封裝它們
  • 對(duì)性能要求特別高 => 考慮用CALayer或OpenGL繪圖

第二章:設(shè)置寄宿圖 - 給圖層提供內(nèi)容


第三章:圖層幾何學(xué)

  • 布局屬性 - 在圖層級(jí)別無法根據(jù)兄弟圖層控制位置和尺寸
    • frame(外 - 父圖層坐標(biāo)系)
    • bounds(內(nèi) - 自身坐標(biāo)系)
    • anchorPoint - 錨點(diǎn)在自身坐標(biāo)系中的(x,y) - 最佳實(shí)例:時(shí)鐘應(yīng)用中的指針轉(zhuǎn)動(dòng)
    • center(UIView)/position(CALayer) - ?錨點(diǎn)在父圖層坐標(biāo)系中的(x,y)

第四章:視覺效果

  • 圓角 - conrnerRadius
    • 只影響背景顏色而不影響背景圖片或是子圖層
    • 通常結(jié)合masksToBounds使用难述,來裁剪子圖層和背景圖片
  • 圖層邊框 - borderWidth和borderColor
  • 邊框是繪制在圖層邊界里面的,而且在所有子內(nèi)容之前吐句,也在子圖層之前胁后。
  • 實(shí)現(xiàn)邊框不遮擋內(nèi)容的兩種做法
    • 使用帶邊框效果的寄宿圖
    • 讓邊框和內(nèi)容解除父子關(guān)系,并讓內(nèi)容在圖層樹中靠前
  • 陰影 - shadowOpacity嗦枢、shadowColor攀芯、shadowOffset(方向和距離)和shadowRadius(模糊度)

    • 與邊框不同
      • 圖層的陰影繼承自內(nèi)容(包含寄宿圖和子視圖)的外形,而不是根據(jù)邊界和角半徑來確定文虏。
      • 陰影可能在圖層邊界之外侣诺;會(huì)被masksToBounds裁剪掉
      • 解決方案:使用兩個(gè)圖層(一個(gè)只畫陰影的空的外圖層和一個(gè)用masksToBounds裁剪內(nèi)容的內(nèi)圖層)
    • shadowPath - 提高性能,CGPathRef類型
  • 圖層蒙板

    • mask - 類似于一個(gè)子圖層氧秘,但它定義的是父圖層的部分可見區(qū)域
    • 比conrnerRadius+masksToBounds更靈活:蒙板圖不局限于靜態(tài)圖年鸳,以通過編碼甚至動(dòng)畫的方式實(shí)時(shí)生成,而且讓子圖層或子視圖裁剪成同樣的形狀
  • 拉伸過濾

  • 較小的圖或者是差異特別明顯丸相、極少斜線的大圖搔确,Nearest會(huì)保留這種差異明顯的特質(zhì)以呈現(xiàn)更好的結(jié)果
  • 對(duì)于大多數(shù)的圖尤其是有很多斜線或曲線輪廓的圖片,選用kCAFilterLinear或kCAFilterTrilinear
  • 組透明
    • alpha(UIView)、opacity(CALayer)都會(huì)影響子層級(jí)
      組透明設(shè)置造成的像素合成
    • 組透明整體實(shí)現(xiàn)方案(解決上述透明度混合造成顯示不一致的問題)
      • UIViewGroupOpacity -> YES(Info.plist)
      • allowsGroupOpacity(IOS7+可用膳算,相當(dāng)于UIViewGroupOpacity)
      • shouldRasterize+rasterizationScale(配置屏幕)座硕,如果它被設(shè)置為YES,在應(yīng)用透明度之前畦幢,圖層及其子圖層都會(huì)被整合成一個(gè)整體的圖片

第五章:變換

  • CGAffineTransform
    • “仿射”:圖層中平行的兩條線在變換之后仍然保持平行
    • 混合變換 - 變換的順序會(huì)影響最終的結(jié)果坎吻,也就是說旋轉(zhuǎn)之后的平移和平移之后的旋轉(zhuǎn)結(jié)果可能不同
  • CATransform3D
    • 透視投影 - m34 = -1.0/d缆蝉,d代表了假想中視角相機(jī)和屏幕之間的距離宇葱,通常設(shè)置為500~1000
    • 滅點(diǎn) - anchorPointZ+anchorPoint,旋轉(zhuǎn)和縮放的不變點(diǎn) => sublayerTransform
    • 背面 - doubleSided屬性刊头,區(qū)別:doubleSided不影響事件響應(yīng)黍瞧,設(shè)置hidden或alpha為0不會(huì)響應(yīng)事件
  • 固體對(duì)象
    • 光亮和陰影 - GLKMatrix3Xxx和GLKVector3Xxx方法
    • 如何讓圖層順序靠前(響應(yīng)鏈中靠后)的圖層得到事件響應(yīng)
      • bringSubviewToFront、sendSubviewToBack原杂、exchangeSubviewAtIndex(_:withSubviewAtIndex:)等方法可以同時(shí)改變顯示順序和圖層順序(響應(yīng)鏈優(yōu)先級(jí))
      • 通過將優(yōu)先級(jí)更高的UIView的userInteractionEnabled設(shè)置為NO

第六章:專用圖層 +(Class)layerClass

  • CAShapeLayer - 通過矢量圖形而不是bitmap來繪制寄宿圖的圖層子類
    • 相比在CALayer中繪制路徑而言優(yōu)勢(shì)如下:
      • 渲染快速(硬件加速)
      • 高效使用內(nèi)存(不需要寄宿圖)
      • 不會(huì)被圖層邊界剪裁掉(可以在邊界之外繪制)
      • 不會(huì)出現(xiàn)像素化(因?yàn)槭鞘噶繄D形)
    • 屬性
      • fillColor印颤、strokeColor、lineWidth(單位:點(diǎn))穿肄、lineCap年局、lineJoin
      • path - UIBezierPath.CGPath
    • 圓角 - 相比使用cornerRadius更靈活
  • CATextLayer - 使用了Core text,渲染非诚滩快
    • 屬性
      • string - (富文本使用NSAttributedString)
      • font 和 fontSize矢否、wrapped(自動(dòng)換行)、truncationMode(截?cái)嗄J?脑溢、alignmentMode
    • 文本像素化
textLayer.contentsScale = UIScreen.mainScreen().scale
  • UILabel替代品 - 用CATextLayer作為宿主圖層的UILabel子類僵朗,可以隨著視圖自動(dòng)調(diào)整大小而且也沒有冗余的寄宿圖
  • CATransformLayer

    • 不能顯示自己的內(nèi)容,只有當(dāng)存在了一個(gè)能作用于子圖層的變換它才真正存在屑彻,而且變換將對(duì)所有子圖層的3D場(chǎng)景生效而不是扁平化后的子圖層验庙。
    • CATransformLayer并不平面化它的子圖層,所以它能夠用于構(gòu)造一個(gè)層級(jí)的3D結(jié)構(gòu)
  • CAGradientLayer

    • 用來生成兩種或更多顏色平滑漸變社牲,繪制使用了硬件加速
    • 基礎(chǔ)漸變
      • startPoint和endPoint
      • colors(CGColorRef數(shù)組)
    • 多重漸變
      • locations屬性
      • 以NSNumber包裝的浮點(diǎn)數(shù)值數(shù)組粪薛,定義了colors屬性中每個(gè)不同顏色的位置(以單位坐標(biāo)系標(biāo)定)
      • 確保數(shù)組大小和colors數(shù)組大小一定要相同
  • CAReplicatorLayer

    • 高效生成許多相似的圖層,并在每個(gè)復(fù)制體上應(yīng)用不同的變換搏恤。
    • 屬性
      • instanceCount
      • instanceTransform
      • instanceRed/Green/BlueOffset违寿、instanceAlphaOffset
      • ……
    • 反射 - ReflectionView
  • CAScrollLayer

    • -scrollToPoint:方法,自動(dòng)適應(yīng)bounds的原點(diǎn)以便圖層內(nèi)容出現(xiàn)在滑動(dòng)的地方
    • 并不負(fù)責(zé)將觸摸事件轉(zhuǎn)換為滑動(dòng)事件挑社,既不渲染滾動(dòng)條陨界,也不實(shí)現(xiàn)任何iOS指定行為例如滑動(dòng)反彈(當(dāng)視圖滑動(dòng)超多了它的邊界的將會(huì)反彈回正確的地方)。
    • UIScrollView并沒有用CAScrollLayer痛阻,事實(shí)上菌瘪,就是簡(jiǎn)單的通過直接操作圖層邊界來實(shí)現(xiàn)滑動(dòng)。
var visibleRect: CGRect { get }
func scrollPoint(_ p: CGPoint)  // 從圖層樹中查找并找到第一個(gè)可用的CAScrollLayer,然后滑動(dòng)它使得指定點(diǎn)成為可視的
func scrollToRect(_ r: CGRect)  // 類似俏扩,不過是使指定矩形可視
  • CATiledLayer
    • OpenGL有一個(gè)最大的紋理尺寸(通常是20482048或40964096糜工,這個(gè)取決于設(shè)備型號(hào)),如果你想在單個(gè)紋理中顯示一個(gè)比這大的圖录淡,即便圖片已經(jīng)存在于內(nèi)存中了捌木,你仍然會(huì)遇到很大的性能問題。所以需要使用類似CATiledLayer的技術(shù)
-(void)drawLayer:(CATiledLayer *)layer inContext:(CGContextRef)ctx //在此根據(jù)需要加載不同的tile
class func fadeDuration() -> CFTimeInterval
tileLayer.contentsScale = [UIScreen mainScreen].scale;

CAEmitterLayer看上去像是許多CAEmitterCell的容器嫉戚,這些CAEmitierCell定義了一個(gè)例子效果刨裆。你將會(huì)為不同的例子效果定義一個(gè)或多個(gè)CAEmitterCell作為模版,同時(shí)CAEmitterLayer負(fù)責(zé)基于這些模版實(shí)例化一個(gè)粒子流彬檀。一個(gè)CAEmitterCell類似于一個(gè)CALayer:它有一個(gè)contents屬性可以定義為一個(gè)CGImage帆啃,另外還有一些可設(shè)置屬性控制著表現(xiàn)和行為。

- 一個(gè)高性能的粒子引擎窍帝,被用來創(chuàng)建實(shí)時(shí)粒子動(dòng)畫如:煙霧努潘,火,雨等等這些效果坤学。
- 自身屬性
  + emitterCells
  + preservesDepth
  + renderMode
    - kCAEmitterLayerAdditive是疊加效果疯坤,其他是覆蓋效果
- [CAEmitterCell](https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CAEmitterCell_class/)的屬性
 + contents、color 
 + birthRate
 + lifetime 深浮、lifetimeRange - 類似velocity
 + alphaSpeed 
 + velocity压怠、velocityRange - [velocity~(velocity+velocityRange)]定義了速度變化范圍
 + emissionLatitude(z軸)、emissionLongitude(xy平面)略号、emissionRange(環(huán)繞發(fā)射角度的一個(gè)圓錐范圍)
  • CAEAGLLayer
    • OpenGL沒有對(duì)象或是圖層的繼承概念刑峡,它的全部工作就是處理3D空間中有顏色和紋理的三角形
    • GLKView(GLKit框架) + CAEAGLLayer(QuartzCore)
    • 重要元素
class func setCurrentContext(_ context: EAGLContext!) -> Bool
func renderbufferStorage(_ target: Int, fromDrawable drawable: EAGLDrawable!) -> Bool
func presentRenderbuffer(_ target: Int) -> Bool
 + CAEAGLLayer的[drawableProperties屬性](https://developer.apple.com/library/ios/documentation/iPhone/Reference/EAGLDrawable_Ref/index.html#//apple_ref/occ/intfp/EAGLDrawable/drawableProperties)(EAGLDrawable協(xié)議)
 + [GLKBaseEffect](https://developer.apple.com/library/ios/documentation/GLkit/Reference/GLKBaseEffect_ClassRef/) - 著色邏輯:func prepareToDraw()
 + glXxx系列方法(setupBuffers & drawFrame)
  • AVPlayerLayer
    • 由AVFoundation框架提供 (不同于其他CALayer由Core Animation框架提供)
    • 播放控制和展現(xiàn)分離:AVPlayer和AVPlayerLayer
      • AVPlayer - play()、pause()玄柠、rate等
      • AVPlayerLayer - player屬性和init(player player: AVPlayer)
        • 繼承了父類CALayer的所有特性突梦,不會(huì)受限于要在一個(gè)矩形中播放視頻;
        • 可實(shí)現(xiàn)3D羽利、圓角宫患、有色邊框、蒙板这弧、陰影等效果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末娃闲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子匾浪,更是在濱河造成了極大的恐慌皇帮,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛋辈,死亡現(xiàn)場(chǎng)離奇詭異属拾,居然都是意外死亡将谊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門渐白,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尊浓,“玉大人,你說我怎么就攤上這事纯衍《俺荩” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵襟诸,是天一觀的道長(zhǎng)瓦堵。 經(jīng)常有香客問我谷丸,道長(zhǎng)堡掏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任泉唁,我火速辦了婚禮,結(jié)果婚禮上亭畜,老公的妹妹穿的比我還像新娘。我一直安慰自己拴鸵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布八堡。 她就那樣靜靜地躺著,像睡著了一般兄渺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上汰现,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天挂谍,我揣著相機(jī)與錄音,去河邊找鬼瞎饲。 笑死口叙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嗅战。 我是一名探鬼主播妄田,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了形庭?” 一聲冷哼從身側(cè)響起铅辞,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎萨醒,沒想到半個(gè)月后斟珊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡富纸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年囤踩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晓褪。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡堵漱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涣仿,到底是詐尸還是另有隱情勤庐,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布好港,位于F島的核電站愉镰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏钧汹。R本人自食惡果不足惜丈探,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拔莱。 院中可真熱鬧碗降,春花似錦、人聲如沸塘秦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赋兵。三九已至霹期,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間甩十,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工鸭轮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窃爷,地道東北人按厘。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓逮京,卻偏偏與公主長(zhǎng)得像懒棉,于是被迫代替她去往敵國(guó)和親麦箍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容