W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
CALayer 有一個(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開(kāi)發(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è)方法:
layer.contents = (__bridge id)image.CGImage;
如果你沒(méi)有使用ARC(自動(dòng)引用計(jì)數(shù)),你就不需要__bridge這部分。但是,你干嘛不用ARC?!
讓我們來(lái)繼續(xù)修改我們?cè)诘谝徽滦陆ǖ墓こ?,以便能夠展示一張圖片而不僅僅是一個(gè)背景色。我們已經(jīng)用代碼的方式建立一個(gè)圖層,那我們就不需要額外的圖層了。那么我們就直接把layerView的宿主圖層的contents
屬性設(shè)置成圖片。
清單2.1 更新后的代碼。
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad]; //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
圖表2.1 在UIView的宿主圖層中顯示一張圖片
我們用這些簡(jiǎn)單的代碼做了一件很有趣的事情:我們利用CALayer在一個(gè)普通的UIView中顯示了一張圖片。這不是一個(gè)UIImageView,它不是我們通常用來(lái)展示圖片的方法。通過(guò)直接操作圖層,我們使用了一些新的函數(shù),使得UIView更加有趣了。
contentGravity
你可能已經(jīng)注意到了我們的雪人看起來(lái)有點(diǎn)。。。胖 ==! 我們加載的圖片并不剛好是一個(gè)方的,為了適應(yīng)這個(gè)視圖,它有一點(diǎn)點(diǎn)被拉伸了。在使用UIImageView的時(shí)候遇到過(guò)同樣的問(wèn)題,解決方法就是把contentMode
屬性設(shè)置成更合適的值,像這樣:
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
可選的常量值有以下一些:
和cotentMode
一樣,contentsGravity
的目的是為了決定內(nèi)容在圖層的邊界中怎么對(duì)齊,我們將使用kCAGravityResizeAspect,它的效果等同于UIViewContentModeScaleAspectFit, 同時(shí)它還能在圖層中等比例拉伸以適應(yīng)圖層的邊界。
self.layerView.layer.contentsGravity = kCAGravityResizeAspect;
圖2.2 可以看到結(jié)果
圖2.3 用錯(cuò)誤的contentsScale
屬性顯示Retina圖片
如你所見(jiàn),我們的雪人不僅有點(diǎn)大還有點(diǎn)像素的顆粒感。那是因?yàn)楹蚒IImage不同,CGImage沒(méi)有拉伸的概念。當(dāng)我們使用UIImage類去讀取我們的雪人圖片的時(shí)候,他讀取了高質(zhì)量的Retina版本的圖片。但是當(dāng)我們用CGImage來(lái)設(shè)置我們的圖層的內(nèi)容時(shí),拉伸這個(gè)因素在轉(zhuǎn)換的時(shí)候就丟失了。不過(guò)我們可以通過(guò)手動(dòng)設(shè)置contentsScale
來(lái)修復(fù)這個(gè)問(wèn)題(如2.2清單),圖2.4是結(jié)果
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad]; //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; //center the image
self.layerView.layer.contentsGravity = kCAGravityCenter;
//set the contentsScale to match image
self.layerView.layer.contentsScale = image.scale;
}
@end
圖2.5 使用masksToBounds
來(lái)修建圖層內(nèi)容
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):
默認(rèn)的contentsRect
是{0, 0, 1, 1},這意味著整個(gè)寄宿圖默認(rèn)都是可見(jiàn)的,如果我們指定一個(gè)小一點(diǎn)的矩形,圖片就會(huì)被裁剪(如圖2.6)
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: