因為現(xiàn)在手頭上的項目而著重研究了一下CALayer的使用,發(fā)現(xiàn)這個類完全就是UI實現(xiàn)的新大陸。在之前項目中以及面試開發(fā)時發(fā)現(xiàn),正常做常規(guī)社交或者信息展示類app的開發(fā)同學接觸到的CALayer也只局限于設(shè)置個圓角邊框之類(可能相比之下我之前的知識面比較狹小?)??傊?,深入學習了CALayer之后會更深一步領(lǐng)悟到UI控件各種屬性的真諦,比如新手困惑frame跟bounds跟transform的關(guān)系。更能實現(xiàn)一些意想不到的UI效果,比如展示控件的3D效果、遮蓋效果以及漸變、粒子啦,現(xiàn)在開發(fā)的項目的實現(xiàn)核心功能正是通過CALayer的實現(xiàn)來完成。(部分內(nèi)容為轉(zhuǎn)載)
1.
CALayer包含在QuartzCore框架中,這是一個跨平臺的框架,既可以用在iOS中又可以用在Mac OS X中。
2.
在iOS中CALayer的設(shè)計主要是了為了內(nèi)容展示和動畫操作,CALayer本身并不包含在UIKit中,它不能響應事件。所以在使用過程中,需要通過手勢來控制CAlayer的屬性變化(transform啦等等)時需要用一個view來接收手勢(touch事件或者GuestureRecognizer),并在事件響應方法中實現(xiàn)CAlayer的變化。
3.
由于CALayer在設(shè)計之初就考慮它的動畫操作功能,CALayer很多屬性在修改時都能形成動畫效果,這種屬性稱為“隱式動畫屬性”。但是對于UIView的根圖層(view.layer)而言屬性的修改并不形成動畫效果,因為很多情況下根圖層更多的充當容器的做用,如果它的屬性變動形成動畫效果會直接影響子圖層。
4.
UIView負責創(chuàng)建并管理CALayer。比如一個:viewA上add了一個viewB,則viewB.layer也成為了viewA.layer的sublayer。
5.
CALayer的各種屬性:
contents:id類型,就是啥類型都能對他賦值都不會報錯,但是賦值完看上去有效果的只有圖片類型。IOS開發(fā)中具體實現(xiàn)為:view.layer.contents = (id)[UIImage imageNamed:"XXX"].CGImage; 聽說MAC開發(fā)中需要用NSImage。UIImageView內(nèi)部就使用這個東西實現(xiàn)圖片顯示。
contentGravity = view.contentMode
contentsScale = view.contentScaleFactor
maskToBounds = view.clipToBounds
contentsRect:跟contents有關(guān)系的屬性,就是規(guī)定了contents的可視區(qū)域。但是通過這個設(shè)置的可視區(qū)域只能為一個矩形區(qū)域。。
contentsCenter:CGRect類型,規(guī)定了contents的放大區(qū)域,當設(shè)置contentsScale時這個區(qū)域就變大啦,以外區(qū)域就縮小啦
6.
(這段完全是載的)CGImage并不是唯一可以賦值給contents屬性的,也可以使用Core Graphics繪制寄宿圖給它,如果你實現(xiàn)了drawRect方法,然后如果你調(diào)用setNeedsDisplay或者外觀屬性被改變時,它就會自動調(diào)用drawRect自動重繪,雖然drawRet是一個UIView方法,但是其實都是底層都是CALayer重繪保存了圖片,如果你不需要自定義繪制就不要寫一個空的drawRect方法,它很消耗cpu和內(nèi)存資源,CALayer有一個可選的delegate屬性,如果設(shè)置了delegate,并主動調(diào)用了layer的displey方法(注意和drawRect不同這個重繪時機是開發(fā)者自己控制的,也可以調(diào)用setNeedsDisplay方法給系統(tǒng)自己找時機調(diào)用),它會調(diào)用displayLayer方法,在這里是設(shè)置contents屬性的最后機會了,如果你沒有實現(xiàn)這個方法,它會嘗試去調(diào)用下面這個方法:drawLayer。。。,如果你實現(xiàn)了displayLayer方法,drawLayer就不會調(diào)用了
7.
其實!UIView的frame、bounds、center、transform這些屬性只是存取方法!真正實現(xiàn)UIView顯示出來的樣子的都是通過這個控件的layer來實現(xiàn)。所以
view.center = view.layer.position?
為對應父圖層的anchorPoint的所在位置,也就是該view在他的父視圖坐標中的view的中心點位置。(這段也是載的)CALayer通過anchorPoint(錨點)和center(position)對齊來控制UIView的位置,錨點是相對UIView的一個位置,而center就是一個點,由于anchorPoint屬性對UIView是屏蔽的,而anchorPoint默認值又是{0.5,0.5},所以這個屬性才叫center.而UIView和CALayertransform旋轉(zhuǎn)也是圍繞這anchorPoint旋轉(zhuǎn)的。
view.frame = view.layer.frame ? ?
frame是通過bounds、position、transform來得出的,比如說view通過transform放大了2倍,那frame中的width跟height就比bounds中的大了2倍,所以進行transform后frame不一定等于bounds
view.bounds = view.layer.bounds
view.transform = view.layer.CGAffineTransform?
layer共有兩個transform的屬性:CGAffineTransform、CATransform3D,我的理解是CGAffineTransform是CATransform3D的一個平面映射,這里有很深的套路啊,有時間專門再寫一篇transform的理解跟我在使用時遇到的問題。
其他layer有關(guān)位置的屬性:
geometryFlipped 這個用來翻轉(zhuǎn)layer所在的坐標系,上下翻!就是!y軸負的跟正的翻!
zPosition 看名字就能明白是用來設(shè)置layer的層級位置的,默認為0,越大越往上!
8.
關(guān)于layer的自適應:
UIView在做自適應時候我們可以采取autoresizingMask、autoLayout或者巨好用的masonry來實現(xiàn)。但是!IOS平臺的Layer并不能像View這樣優(yōu)雅地自適應!聽說只有MAC開發(fā)才行。。。所以導致我在開發(fā)項目過程中不能全程使用masonry。。。想做ios中l(wèi)ayer層的自適應也是有辦法的,比如你可以遵循layer的代理,然后在layoutSublayersOfLayer代理方法中實現(xiàn),這樣當然免不了一堆的判斷跟計算啦。