W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
CALayer 有一個屬性叫做contents
,這個屬性的類型被定義為id,意味著它可以是任何類型的對象。在這種情況下,你可以給contents
屬性賦任何值,你的app仍然能夠編譯通過。但是,在實踐中,如果你給contents
賦的不是CGImage,那么你得到的圖層將是空白的。
contents
這個奇怪的表現(xiàn)是由Mac OS的歷史原因造成的。它之所以被定義為id類型,是因為在Mac OS系統(tǒng)上,這個屬性對CGImage和NSImage類型的值都起作用。如果你試圖在iOS平臺上將UIImage的值賦給它,只能得到一個空白的圖層。一些初識Core Animation的iOS開發(fā)者可能會對這個感到困惑。
頭疼的不僅僅是我們剛才提到的這個問題。事實上,你真正要賦值的類型應該是CGImageRef,它是一個指向CGImage結構的指針。UIImage有一個CGImage屬性,它返回一個"CGImageRef",如果你想把這個值直接賦值給CALayer的contents
,那你將會得到一個編譯錯誤。因為CGImageRef并不是一個真正的Cocoa對象,而是一個Core Foundation類型。
盡管Core Foundation類型跟Cocoa對象在運行時貌似很像(被稱作toll-free bridging),他們并不是類型兼容的,不過你可以通過bridged關鍵字轉換。如果要給圖層的寄宿圖賦值,你可以按照以下這個方法:
layer.contents = (__bridge id)image.CGImage;
如果你沒有使用ARC(自動引用計數(shù)),你就不需要__bridge這部分。但是,你干嘛不用ARC?!
讓我們來繼續(xù)修改我們在第一章新建的工程,以便能夠展示一張圖片而不僅僅是一個背景色。我們已經(jīng)用代碼的方式建立一個圖層,那我們就不需要額外的圖層了。那么我們就直接把layerView的宿主圖層的contents
屬性設置成圖片。
清單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的宿主圖層中顯示一張圖片
我們用這些簡單的代碼做了一件很有趣的事情:我們利用CALayer在一個普通的UIView中顯示了一張圖片。這不是一個UIImageView,它不是我們通常用來展示圖片的方法。通過直接操作圖層,我們使用了一些新的函數(shù),使得UIView更加有趣了。
contentGravity
你可能已經(jīng)注意到了我們的雪人看起來有點。。。胖 ==! 我們加載的圖片并不剛好是一個方的,為了適應這個視圖,它有一點點被拉伸了。在使用UIImageView的時候遇到過同樣的問題,解決方法就是把contentMode
屬性設置成更合適的值,像這樣:
view.contentMode = UIViewContentModeScaleAspectFit;
這個方法基本和我們遇到的情況的解決方法已經(jīng)接近了(你可以試一下 :) ),不過UIView大多數(shù)視覺相關的屬性比如contentMode
,對這些屬性的操作其實是對對應圖層的操作。
CALayer與contentMode
對應的屬性叫做contentsGravity
,但是它是一個NSString類型,而不是像對應的UIKit部分,那里面的值是枚舉。contentsGravity
可選的常量值有以下一些:
和cotentMode
一樣,contentsGravity
的目的是為了決定內容在圖層的邊界中怎么對齊,我們將使用kCAGravityResizeAspect,它的效果等同于UIViewContentModeScaleAspectFit, 同時它還能在圖層中等比例拉伸以適應圖層的邊界。
self.layerView.layer.contentsGravity = kCAGravityResizeAspect;
圖2.2 可以看到結果
圖2.3 用錯誤的contentsScale
屬性顯示Retina圖片
如你所見,我們的雪人不僅有點大還有點像素的顆粒感。那是因為和UIImage不同,CGImage沒有拉伸的概念。當我們使用UIImage類去讀取我們的雪人圖片的時候,他讀取了高質量的Retina版本的圖片。但是當我們用CGImage來設置我們的圖層的內容時,拉伸這個因素在轉換的時候就丟失了。不過我們可以通過手動設置contentsScale
來修復這個問題(如2.2清單),圖2.4是結果
@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
來修建圖層內容
CALayer的contentsRect
屬性允許我們在圖層邊框里顯示寄宿圖的一個子域。這涉及到圖片是如何顯示和拉伸的,所以要比contentsGravity
靈活多了
和bounds
,frame
不同,contentsRect
不是按點來計算的,它使用了單位坐標,單位坐標指定在0到1之間,是一個相對值(像素和點就是絕對值)。所以他們是相對與寄宿圖的尺寸的。iOS使用了以下的坐標系統(tǒng):
默認的contentsRect
是{0, 0, 1, 1},這意味著整個寄宿圖默認都是可見的,如果我們指定一個小一點的矩形,圖片就會被裁剪(如圖2.6)
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: