這個(gè)我是在cocochina上面看到的 原文地址http://www.cocoachina.com/ios/20150104/10814.html
CALyer 有一個(gè)屬性叫做contents,這個(gè)屬性的類型被定義為id,意味著它可以是任何類型的對(duì)象。在這種情況下,你可以給contents屬性賦任何值,你的app仍然能夠編譯通過(guò)。但是,在實(shí)踐中,如果你給contents賦的不是CGImage,那么你得到的圖層將是空白的。
contents這個(gè)奇怪的表現(xiàn)是由Mac OS的歷史原因造成的。它之所以被定義為id類型,是因?yàn)樵贛ac OS系統(tǒng)上,這個(gè)屬性對(duì)CGImage和NSImage類型的值都起作用。如果你試圖在iOS平臺(tái)上將UIImage的值賦給它,只能得到一個(gè)空白的圖層。一些初識(shí)Core Animation的iOS開發(fā)者可能會(huì)對(duì)這個(gè)感到困惑。
頭疼的不僅僅是我們剛才提到的這個(gè)問(wèn)題。事實(shí)上,你真正要賦值的類型應(yīng)該是CGImageRef,它是一個(gè)指向CGImage結(jié)構(gòu)的指針。UIImage有一個(gè)CGImage屬性,它返回一個(gè)"CGImageRef",如果你想把這個(gè)值直接賦值給CALayer的contents,那你將會(huì)得到一個(gè)編譯錯(cuò)誤。因?yàn)镃GImageRef并不是一個(gè)真正的Cocoa對(duì)象,而是一個(gè)Core Foundation類型。
盡管Core Foundation類型跟Cocoa對(duì)象在運(yùn)行時(shí)貌似很像(被稱作toll-free bridging),他們并不是類型兼容的,不過(guò)你可以通過(guò)bridged關(guān)鍵字轉(zhuǎn)換。如果要給圖層的寄宿圖賦值,你可以按照以下這個(gè)方法:
1
layer.contents?=?(__bridge?id)image.CGImage;
如果你沒(méi)有使用ARC(自動(dòng)引用計(jì)數(shù)),你就不需要__bridge這部分。但是,你干嘛不用ARC?!
讓我們來(lái)繼續(xù)修改我們?cè)诘谝徽滦陆ǖ墓こ蹋员隳軌蛘故疽粡垐D片而不僅僅是一個(gè)背景色。我們已經(jīng)用代碼的方式建立一個(gè)圖層,那我們就不需要額外的圖層了。那么我們就直接把layerView的宿主圖層的contents屬性設(shè)置成圖片。
清單2.1 更新后的代碼。
@implementation?ViewController
-?(void)viewDidLoad
{
[superviewDidLoad];//load?an?image
UIImage?*image?=?[UIImage?imageNamed:@"Snowman.png"];
//add?it?directly?to?our?view's?layer
self.layerView.layer.contents?=?(__bridge?id)image.CGImage;
}
@end
contentGravity
你可能已經(jīng)注意到了我們的雪人看起來(lái)有點(diǎn)。。。胖 ==! 我們加載的圖片并不剛好是一個(gè)方的,為了適應(yīng)這個(gè)視圖,它有一點(diǎn)點(diǎn)被拉伸了。在使用UIImageView的時(shí)候遇到過(guò)同樣的問(wèn)題,解決方法就是把contentMode屬性設(shè)置成更合適的值,像這樣:
1
view.contentMode?=?UIViewContentModeScaleAspectFit;
這個(gè)方法基本和我們遇到的情況的解決方法已經(jīng)接近了(你可以試一下 :) ),不過(guò)UIView大多數(shù)視覺(jué)相關(guān)的屬性比如contentMode,對(duì)這些屬性的操作其實(shí)是對(duì)對(duì)應(yīng)圖層的操作。
CALayer與contentMode對(duì)應(yīng)的屬性叫做contentsGravity,但是它是一個(gè)NSString類型,而不是像對(duì)應(yīng)的UIKit部分,那里面的值是枚舉。contentsGravity可選的常量值有以下一些:
?kCAGravityCenter
kCAGravityTop
kCAGravityBottom
kCAGravityLeft
kCAGravityRight
kCAGravityTopLeft
kCAGravityTopRight
kCAGravityBottomLeft
kCAGravityBottomRight
kCAGravityResize
kCAGravityResizeAspect
kCAGravityResizeAspectFill
和cotentMode一樣,contentsGravity的目的是為了決定內(nèi)容在圖層的邊界中怎么對(duì)齊,我們將使用kCAGravityResizeAspect,它的效果等同于UIViewContentModeScaleAspectFit, 同時(shí)它還能在圖層中等比例拉伸以適應(yīng)圖層的邊界。
1
self.layerView.layer.contentsGravity?=?kCAGravityResizeAspect;
contentsScale
contentsScale屬性定義了寄宿圖的像素尺寸和視圖大小的比例,默認(rèn)情況下它是一個(gè)值為1.0的浮點(diǎn)數(shù)。
contentsScale的目的并不是那么明顯。它并不是總會(huì)對(duì)屏幕上的寄宿圖有影響。如果你嘗試對(duì)我們的例子設(shè)置不同的值,你就會(huì)發(fā)現(xiàn)根本沒(méi)任何影響。因?yàn)閏ontents由于設(shè)置了contentsGravity屬性,所以它已經(jīng)被拉伸以適應(yīng)圖層的邊界。
如果你只是單純地想放大圖層的contents圖片,你可以通過(guò)使用圖層的transform和affineTransform屬性來(lái)達(dá)到這個(gè)目的(見(jiàn)第五章『Transforms』,里面對(duì)此有解釋),這(指放大)也不是contengsScale的目的所在.
contentsScale屬性其實(shí)屬于支持高分辨率(又稱Hi-DPI或Retina)屏幕機(jī)制的一部分。它用來(lái)判斷在繪制圖層的時(shí)候應(yīng)該為寄宿圖創(chuàng)建的空間大小,和需要顯示的圖片的拉伸度(假設(shè)并沒(méi)有設(shè)置contentsGravity屬性)。UIView有一個(gè)類似功能但是非常少用到的contentScaleFactor屬性。
如果contentsScale設(shè)置為1.0,將會(huì)以每個(gè)點(diǎn)1個(gè)像素繪制圖片,如果設(shè)置為2.0,則會(huì)以每個(gè)點(diǎn)2個(gè)像素繪制圖片,這就是我們熟知的Retina屏幕。(如果你對(duì)像素和點(diǎn)的概念不是很清楚的話,這個(gè)章節(jié)的后面部分將會(huì)對(duì)此做出解釋)。
maskToBounds
現(xiàn)在我們的雪人總算是顯示了正確的大小,不過(guò)你也許已經(jīng)發(fā)現(xiàn)了另外一些事情:他超出了視圖的邊界。默認(rèn)情況下,UIView仍然會(huì)繪制超過(guò)邊界的內(nèi)容或是子視圖,在CALayer下也是這樣的。
UIView有一個(gè)叫做clipsToBounds的屬性可以用來(lái)決定是否顯示超出邊界的內(nèi)容,CALayer對(duì)應(yīng)的屬性叫做masksToBounds,把它設(shè)置為YES,雪人就在邊界里啦~(如圖2.5)
contentsRect
CALayer的contentsRect屬性允許我們?cè)趫D層邊框里顯示寄宿圖的一個(gè)子域。這涉及到圖片是如何顯示和拉伸的,所以要比contentsGravity靈活多了
和bounds,frame不同,contentsRect不是按點(diǎn)來(lái)計(jì)算的,它使用了單位坐標(biāo),單位坐標(biāo)指定在0到1之間,是一個(gè)相對(duì)值(像素和點(diǎn)就是絕對(duì)值)。所以他們是相對(duì)與寄宿圖的尺寸的。iOS使用了以下的坐標(biāo)系統(tǒng):
點(diǎn) —— 在iOS和Mac OS中最常見(jiàn)的坐標(biāo)體系。點(diǎn)就像是虛擬的像素,也被稱作邏輯像素。在標(biāo)準(zhǔn)設(shè)備上,一個(gè)點(diǎn)就是一個(gè)像素,但是在Retina設(shè)備上,一個(gè)點(diǎn)等于2*2個(gè)像素。iOS用點(diǎn)作為屏幕的坐標(biāo)測(cè)算體系就是為了在Retina設(shè)備和普通設(shè)備上能有一致的視覺(jué)效果。
像素 —— 物理像素坐標(biāo)并不會(huì)用來(lái)屏幕布局,但是仍然與圖片有相對(duì)關(guān)系。UIImage是一個(gè)屏幕分辨率解決方案,所以指定點(diǎn)來(lái)度量大小。但是一些底層的圖片表示如CGImage就會(huì)使用像素,所以你要清楚在Retina設(shè)備和普通設(shè)備上,他們表現(xiàn)出來(lái)了不同的大小。
單位 —— 對(duì)于與圖片大小或是圖層邊界相關(guān)的顯示,單位坐標(biāo)是一個(gè)方便的度量方式, 當(dāng)大小改變的時(shí)候,也不需要再次調(diào)整。單位坐標(biāo)在OpenGL這種紋理坐標(biāo)系統(tǒng)中用得很多,Core Animation中也用到了單位坐標(biāo)。
默認(rèn)的contentsRect是{0, 0, 1, 1},這意味著整個(gè)寄宿圖默認(rèn)都是可見(jiàn)的,如果我們指定一個(gè)小一點(diǎn)的矩形,圖片就會(huì)被裁剪(如圖2.6)
contentsCenter
本章我們介紹的最后一個(gè)和內(nèi)容有關(guān)的屬性是contentsCenter,看名字你可能會(huì)以為它可能跟圖片的位置有關(guān),不過(guò)這名字著實(shí)誤導(dǎo)了你。contentsCenter其實(shí)是一個(gè)CGRect,它定義了一個(gè)固定的邊框和一個(gè)在圖層上可拉伸的區(qū)域。 改變contentsCenter的值并不會(huì)影響到寄宿圖的顯示,除非這個(gè)圖層的大小改變了,你才看得到效果。
默認(rèn)情況下,contentsCenter是{0, 0, 1, 1},這意味著如果大?。ㄓ蒫onttensGravity決定)改變了,那么寄宿圖將會(huì)均勻地拉伸開。但是如果我們?cè)黾釉c(diǎn)的值并減小尺寸。我們會(huì)在圖片的周圍創(chuàng)造一個(gè)邊框。圖2.9展示了contentsCenter設(shè)置為{0.25, 0.25, 0.5, 0.5}的效果。