Core Animation 學(xué)習(xí)筆記
Layer的屬性
CALayer 能幫助我們完成很多東西,那么先來看看他都有哪些基本屬性吧。
添加圖片 --- Contents屬性
CALayer 有一個屬性叫做contents,這個屬性的類型被定義為id,意味著它可以是任何類型的對象。在這種情況下,你可以給contents屬性賦任何值,你的app仍然能夠編譯通過。但是,在實踐中,如果你給contents賦的不是CGImage,那么你得到的圖層將是空白的。
contents這個奇怪的表現(xiàn)是由Mac OS的歷史原因造成的。它之所以被定義為id類型,是因為在Mac OS系統(tǒng)上,這個屬性對CGImage和NSImage類型的值都起作用。如果你試圖在iOS平臺上將UIImage的值賦給它,只能得到一個空白的圖層。
事實上,你真正要賦值的類型應(yīng)該是CGImageRef,它是一個指向CGImage結(jié)構(gòu)的指針。UIImage有一個CGImage屬性,它返回一個"CGImageRef",如果你想把這個值直接賦值給CALayer的contents,那你將會得到一個編譯錯誤。因為CGImageRef并不是一個真正的Cocoa對象,而是一個Core Foundation類型。
盡管Core Foundation類型跟Cocoa對象在運行時貌似很像(被稱作toll-free bridging),他們并不是類型兼容的,不過你可以通過bridged關(guān)鍵字轉(zhuǎn)換。如果要給圖層的寄宿圖賦值,你可以按照以下這個方法:
layer.contents = (__bridge id)image.CGImage;
這個時候,我們?nèi)绾谓o我們的UIView 添加一張圖片呢。如下:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.\
UIView *layerView = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
[self.view addSubview:layerView];
UIImage *image = [UIImage imageNamed:@"imageName"];
//add it directly to our view's layer
layerView.layer.contents = (__bridge id)image.CGImage;
}
這個時候 layerView 里面就會有一張 叫 imageName的圖片。可以試著自己搞搞看。
ContentModel --- contentGravity屬性
當(dāng)顯示的圖片不符合要求的尺寸,在UIImageView 中也有這樣的問題,而UIImageView是通過 ContentModel去解決的,那么在layer中一樣有這樣的屬性。
CALayer與contentMode對應(yīng)的屬性叫做contentsGravity,但是它是一個NSString類型,而不是像對應(yīng)的UIKit部分,那里面的值是枚舉。contentsGravity可選的常量值有以下一些:
kCAGravityCenter
kCAGravityTop
kCAGravityBottom
kCAGravityLeft
kCAGravityRight
kCAGravityTopLeft
kCAGravityTopRight
kCAGravityBottomLeft
kCAGravityBottomRight
kCAGravityResize
kCAGravityResizeAspect
kCAGravityResizeAspectFill
和cotentMode一樣,contentsGravity的目的是為了決定內(nèi)容在圖層的邊界中怎么對齊,我們將使用kCAGravityResizeAspect,它的效果等同于UIViewContentModeScaleAspectFit, 同時它還能在圖層中等比例拉伸以適應(yīng)圖層的邊界。
contentsScale屬性
contentsScale屬性定義了寄宿圖的像素尺寸和視圖大小的比例,默認(rèn)情況下它是一個值為1.0的浮點數(shù)。
contentsScale的目的并不是那么明顯。它并不是總會對屏幕上的寄宿圖有影響。如果你嘗試對我們的例子設(shè)置不同的值,你就會發(fā)現(xiàn)根本沒任何影響。因為contents由于設(shè)置了contentsGravity屬性,所以它已經(jīng)被拉伸以適應(yīng)圖層的邊界。
當(dāng)用代碼的方式來處理寄宿圖的時候,一定要記住要手動的設(shè)置圖層的contentsScale屬性,否則,你的圖片在Retina設(shè)備上就顯示得不正確啦。代碼如下:
layer.contentsScale = [UIScreen mainScreen].scale;
自定義Layer
給contents賦CGImage的值不是唯一的設(shè)置寄宿圖的方法。我們也可以直接用Core Graphics直接繪制寄宿圖。能夠通過繼承UIView并實現(xiàn)-drawRect:方法來自定義繪制。
-drawRect: 方法沒有默認(rèn)的實現(xiàn),因為對UIView來說,寄宿圖并不是必須的,它不在意那到底是單調(diào)的顏色還是有一個圖片的實例。如果UIView檢測到-drawRect: 方法被調(diào)用了,它就會為視圖分配一個寄宿圖,這個寄宿圖的像素尺寸等于視圖大小乘以 contentsScale的值。
如果你不需要寄宿圖,那就不要創(chuàng)建這個方法了,這會造成CPU資源和內(nèi)存的浪費,這也是為什么蘋果建議:如果沒有自定義繪制的任務(wù)就不要在子類中寫一個空的-drawRect:方法。
當(dāng)視圖在屏幕上出現(xiàn)的時候 -drawRect:方法就會被自動調(diào)用。-drawRect:方法里面的代碼利用Core Graphics去繪制一個寄宿圖,然后內(nèi)容就會被緩存起來直到它需要被更新(通常是因為開發(fā)者調(diào)用了-setNeedsDisplay方法,盡管影響到表現(xiàn)效果的屬性值被更改時,一些視圖類型會被自動重繪,如bounds屬性)。雖然-drawRect:方法是一個UIView方法,事實上都是底層的CALayer安排了重繪工作和保存了因此產(chǎn)生的圖片。
總結(jié)
介紹了一下CALay的許多屬性。然后就是 如果要自定義layer的話,只要在UIView中實現(xiàn)drawRect方法,在這個方法里面打開圖片上下文進(jìn)行繪制。但是如果你沒有要繪制的layer,請在代碼中盡量不要實現(xiàn)drawRect方法,因為如果你實現(xiàn)了(即使是一個空方法),那么CUP也會給這個UIView分配一個空間去存儲寄宿圖,這樣就造成了不必要的CUP浪費。
通常做法是實現(xiàn)UIView的-drawRect:方法,UIView就會幫你做完剩下的工作,包括在需要重繪的時候調(diào)用-display方法。
參考致謝
http://zsisme.gitbooks.io/ios-/content/chapter2/the-contents-image.html