《iOS Core Animation: Advanced Techniques》筆記

Chapter 1

</br>
Core Animation不是一個嚴(yán)謹(jǐn)?shù)目蚣堋?code>CAAnimation才是一個框架名,它是QuartzCore的一部分袖迎。
Core Animation是用C寫的坛缕,所以要注意類型轉(zhuǎn)換猫牡,用“無縫橋接” __bridge胡诗。
</br>

UIView是視圖,CALayer是圖層淌友。

</br>

UIViewCALayer的關(guān)系:

  • UIView處理用戶交互煌恢,CALayer不管。

  • 每個UIView都有一個CALayer實例的圖層屬性亩进,不能在Interface Builder中設(shè)置UIViewlayer屬性症虑。
    </br>

處理視圖比單獨處理圖層更方便。

Chapter 2

</br>
知識點:

  • CALayercontents屬性
  • UIViewcontentMode屬性和CALayercontentsGravity屬性
  • CALayercontentsScale屬性
  • UIViewclipsToBounds屬性和CALayermaskToBounds屬性
  • CALayercontentsRect屬性
  • CALayercontentsCenter屬性(可在Interface Builder中設(shè)置)
  • CALayerdelegate屬性归薛,遵循CALayerDelegate
  • CALayer-displayer方法

</br>
寄宿圖(圖層中包含的圖):
CALayercontents屬性

UIImage *image = [UIImage imageNamed:@"picture"];
    
self.layerView.layer.contents = (__bridge id)(image.CGImage);

這樣的寄宿圖會在圖層中被拉伸以適應(yīng)視圖的大小谍憔,可以加上下面這句,讓顯示的圖片適應(yīng)原來的比例

self.layerView.contentMode = UIViewContentModeScaleAspectFit;

由此可見主籍,UIView大多數(shù)視覺相關(guān)的屬性比如上面用的contentMode习贫,對這些屬性的操作其實是對對應(yīng)圖層的操作。

CALayercontentMode屬性叫contentsGravity

self.layerView.layer.contentsGravity = kCAGravityResizeAspect;

可以達(dá)到像剛才設(shè)置UIViewcontentMode屬性同樣的效果千元。

注意防止用錯誤的contentsScale去顯示Retina圖片苫昌。CGImage沒有UIImage中的拉伸概念。當(dāng)用UIImage讀取的圖片都是Retina圖片幸海,在UIImage轉(zhuǎn)換為CGImage時祟身,拉伸的元素將會丟失奥务。contentsScale默認(rèn)值為1.0,如果把contentsGravity屬性設(shè)為kCAGravityCenter袜硫,不設(shè)置contentsScale(即采用默認(rèn)值)氯葬,就會出現(xiàn)這種錯誤現(xiàn)實Retina圖片的情況。

正確做法:

UIImage *image = [UIImage imageNamed:@"picture"];
self.layerView.layer.contents = (__bridge id)(image.CGImage);

self.layerView.layer.contentsGravity = kCAGravityCenter;
self.layerView.layer.contentsScale = image.scale;

默認(rèn)情況下婉陷,UIViewCALayer都會繪制超過邊界的內(nèi)容或子視圖帚称。
只要設(shè)置UIView的屬性clipsToBoundsCALayermaskToBounds設(shè)置為YES。就不會超出邊界了秽澳。

self.layerView.clipsToBounds = YES;
//或
self.layerView.layer.maskToBounds = YES;

除了可以使用CALayercontents屬性設(shè)置寄宿圖闯睹,還可以-drawRect方法自定義繪圖,此方法沒有默認(rèn)的實現(xiàn)担神,因為UIView不一定有寄宿圖楼吃,如果不需要寄宿圖,就不要實現(xiàn)此方法杏瞻,否則會浪費資源所刀。

CALayer要顯式調(diào)用-display方法,當(dāng)圖層顯示在屏幕上時捞挥,CALayer不會自動重繪它的內(nèi)容。它把重繪的決定權(quán)交給了開發(fā)者忧吟。
沒有用masksToBounds屬性砌函,繪制的那個圓仍然沿邊界被裁剪了。這是因為使用CALayerDelegate繪制寄宿圖的時候溜族,并沒有對超出邊界外的內(nèi)容提供繪制支持讹俊。

除非你創(chuàng)建了一個單獨的圖層,你幾乎沒有機(jī)會用到CALayerDelegate協(xié)議煌抒。因為當(dāng)UIView創(chuàng)建了它的宿主圖層時仍劈,它就會自動地把圖層的delegate設(shè)置為它自己,并提供了一個-displayLayer:的實現(xiàn)寡壮,那所有的問題就都沒了贩疙。

但是,當(dāng)使用寄宿了視圖的圖層的時候况既,也不必實現(xiàn)-displayLayer:-drawLayer:inContext:方法來繪制你的寄宿圖这溅。通常做法是實現(xiàn)UIView-drawRect:方法,UIView就會幫你做完剩下的工作棒仍,包括在需要重繪的時候調(diào)用-display方法悲靴。
</br>

Chapter 3

</br>
知識點:

  • UIViewframebounds莫其、center屬性和CALayerframe癞尚、bounds耸三、position屬性
  • CALayeranchorPoint屬性
  • CALayerzPosition屬性
  • CALayer-containsPoint:方法和-hitTest:方法

布局

UIView三個重要布局屬性:framebounds浇揩、center
對應(yīng)CALayerframe仪壮、boundsposition临燃。
frame代表了圖層的外部坐標(biāo)(也就是在父圖層上占據(jù)的空間)睛驳,bounds是內(nèi)部坐標(biāo)({0, 0}通常是圖層的左上角),centerposition都代表了相對于父圖anchorPoint所在的位置膜廊。

視圖的frame乏沸,boundscenter屬性僅僅是存取方法,當(dāng)操縱視圖的frame爪瓜,實際上是在改變位于視圖下方CALayerframe蹬跃,不能夠獨立于圖層之外改變視圖的frame。對于視圖或者圖層來說铆铆,frame并不是一個非常清晰的屬性蝶缀,它其實是一個虛擬屬性,是根據(jù)bounds薄货,positiontransform計算而來翁都,所以當(dāng)其中任何一個值發(fā)生改變,frame都會變化谅猾。相反柄慰,改變frame的值同樣會影響到他們當(dāng)中的值。

?View和Layer的坐標(biāo)系關(guān)系

旋轉(zhuǎn)后View和Layer的坐標(biāo)系關(guān)系

當(dāng)對圖層做變換的時候税娜,比如旋轉(zhuǎn)或者縮放坐搔,frame
實際上代表了覆蓋在圖層旋轉(zhuǎn)之后的整個軸對齊的矩形區(qū)域,也就是說frame的寬高可能和bounds的寬高不再一致了敬矩。根據(jù)上圖可以看到這點概行。

錨點

視圖的center屬性和圖層的position屬性都指定了anchorPoint相對于父圖層的位置。圖層的anchorPoint通過position來控制它的frame的位置弧岳,你可以認(rèn)為anchorPoint是用來移動圖層的把柄凳忙。默認(rèn)來說,anchorPoint位于圖層的中點缩筛,所以圖層的將會以這個點為中心放置消略。anchorPoint屬性并沒有被UIView
接口暴露出來嗡贺,這也是視圖的position屬性被叫做“center”的原因愉棱。但是圖層的anchorPoint可以被移動费什,比如你可以把它置于圖層frame的左上角傍药,于是圖層的內(nèi)容將會向右下角的position方向移動汉操,而不是居中了嫂冻。

修改anchorPoint

注意到创坞,當(dāng)改變了anchorPoint府寒,position屬性保持固定的值并沒有發(fā)生改變,但是frame卻移動了伤提。

contentsRectcontentsCenter屬性類似巫俺,anchorPoint單位坐標(biāo)來描述,也就是圖層的相對坐標(biāo)肿男,圖層左上角是{0, 0}介汹,右下角是{1, 1},因此默認(rèn)坐標(biāo)是{0.5, 0.5}舶沛。anchorPoint可以通過指定xy值小于0或者大于1嘹承,使它放置在圖層范圍之外。

鐘擺例子使用anchorPoint

每個時針使用一個UIImageView

運行后 時針的位置很奇怪

給各時針修改錨點:

self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
比較正常的指針

</br>

坐標(biāo)系

和視圖一樣如庭,圖層在圖層樹當(dāng)中也是相對于父圖層按層級關(guān)系放置叹卷,一個圖層的position依賴于它父圖層的bounds,如果父圖層發(fā)生了移動坪它,它的所有子圖層也會跟著移動骤竹。
這樣對于放置圖層會更加方便,因為你可以通過移動根圖層來將它的子圖層作為一個整體來移動往毡,但是有時候你需要知道一個圖層的絕對位置蒙揣,或者是相對于另一個圖層的位置,而不是它當(dāng)前父圖層的位置开瞭。CALayer給不同坐標(biāo)系之間的圖層轉(zhuǎn)換提供了一些工具類方法:

-(CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer *)layer
-(CGPoint)convertPoint:(CGPoint)point toLayer:(CALayer *)layer
-(CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *)layer
-(CGRect)convertRect:(CGRect)rect toLayer:(CALayer *)layer

這些方法可以把定義在一個圖層坐標(biāo)系下的點或者矩形轉(zhuǎn)換成另一個圖層坐標(biāo)系下的點或者矩形鸣奔。

Z坐標(biāo)軸

UIView嚴(yán)格的二維坐標(biāo)系不同,CALayer
存在于一個三維空間當(dāng)中惩阶。除了我們已經(jīng)討論過的positionanchorPoint屬性之外,CALayer還有另外兩個屬性扣汪,zPositionanchorPointZ断楷,二者都是在Z軸上描述圖層位置的浮點類型。
zPosition屬性在大多數(shù)情況下其實并不常用崭别。在第五章冬筒,我們將會涉及CATransform3D,你會知道如何在三維空間移動和旋轉(zhuǎn)圖層茅主,除了做變換之外舞痰,zPosition最實用的功能就是改變圖層的顯示順序了。
通常诀姚,圖層是根據(jù)它們子圖層的sublayers出現(xiàn)的順序來類繪制的响牛,這就是所謂的畫家的算法--就像一個畫家在墻上作畫--后被繪制上的圖層將會遮蓋住之前的圖層,但是通過增加圖層的zPosition,就可以把圖層向相機(jī)方向前置呀打,于是它就在所有其他圖層的前面了(或者至少是小于它的zPosition值的圖層的前面)矢赁。

在IB設(shè)置的層次結(jié)構(gòu)中,greenView在pinkView后面

為greenView圖層設(shè)置zPosition屬性:

self.greenView.layer.zPosition = 1.0f;
運行后贬丛,greenView顯示在pinkView前

Hit Testing

最好使用圖層相關(guān)視圖撩银,而不是創(chuàng)建獨立的圖層關(guān)系。其中一個原因就是要處理額外復(fù)雜的觸摸事件豺憔。
CALayer并不關(guān)心任何響應(yīng)鏈?zhǔn)录罨瘢圆荒苤苯犹幚碛|摸事件或者手勢。但是它有一系列的方法幫你處理事件:-containsPoint:-hitTest:恭应。

-containsPoint:接受一個在本圖層坐標(biāo)系下的CGPoint抄邀,如果這個點在圖層frame范圍內(nèi)就返回YES。下面看例:

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *layerView;
@property (strong, nonatomic) CALayer *blueLayer;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];

    self.blueLayer = [CALayer layer];
    self.blueLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
    self.blueLayer.backgroundColor = [UIColor blueColor].CGColor;
    [self.layerView.layer addSublayer:self.blueLayer];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    CGPoint point = [[touches anyObject] locationInView:self.view];
    point = [self.layerView.layer convertPoint:point fromLayer:self.view.layer];
    if ([self.layerView.layer containsPoint:point]) {
        point = [self.blueLayer convertPoint:point fromLayer:self.layerView.layer];
        if ([self.blueLayer containsPoint:point]) {
            NSLog(@"Inside Blue Layer.");
        } else {
            NSLog(@"Inside White Layer.");
        }
    }
}

效果圖

當(dāng)點擊白色視圖圖層的子圖層時暮屡,打印Inside Blue Layer撤摸,點擊白色視圖圖層時,打印Inside White Layer褒纲。

-hitTest:方法同樣接受一個CGPoint類型參數(shù)准夷,它返回圖層本身,或者包含這個坐標(biāo)點的葉子節(jié)點圖層莺掠。這意味著不再需要像使用-containsPoint:那樣衫嵌,人工地在每個子圖層變換或者測試點擊的坐標(biāo)。如果這個點在最外面圖層的范圍之外彻秆,則返回nil楔绞。具體使用-hitTest:方法被點擊圖層的代碼如下:

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
CGPoint point = [[touches anyObject] locationInView:self.view];
CALayer *layer = [self.layerView.layer hitTest:point];
if (layer == self.blueLayer) {
    NSLog(@"Inside Blue Layer");
} else if (layer == self.layerView.layer) {
    NSLog(@"Inside White Layer");
    }
}

得到跟上面一樣的效果圖

注意當(dāng)調(diào)用圖層的-hitTest:方法時,測算的順序嚴(yán)格依賴于圖層樹當(dāng)中的圖層順序(和UIView處理事件類似)唇兑。之前提到的zPosition屬性可以明顯改變屏幕上圖層的順序酒朵,但不能改變事件傳遞的順序。

這意味著如果改變了圖層的z軸順序扎附,你會發(fā)現(xiàn)將不能夠檢測到最前方的視圖點擊事件蔫耽,這是因為被另一個圖層遮蓋住了,雖然它的zPosition值較小留夜,但是在圖層樹中的順序靠前匙铡。

</br>

Chapter 4

</br>
知識點:

  • CALayercornerRadius屬性
  • CALayerborderWidth屬性
  • CALayerborderColor屬性
  • CALayershadowOpacity屬性
  • CALayershadowColor屬性
  • CALayershadowOffset屬性
  • CALayershadowRadius屬性
  • CALayermask屬性
  • CALayermagnificationFilter屬性和minificationFilter屬性
  • CALayershouldRasterize屬性
  • CALayerrasterizationScale屬性

</br>
制造矩形圓角,用CALayercornerRadius屬性碍粥,CGFloat類型鳖眼,默認(rèn)值為0(直角)。

borderWidth屬性用來設(shè)置圖層的邊界寬度嚼摩,CGFloat類型钦讳。borderColor屬性就是設(shè)置圖層的顏色矿瘦,CGColorRef類型,默認(rèn)為黑色蜂厅。如果圖層的子圖層超過了邊界匪凡,或者是寄宿圖在透明區(qū)域有一個透明蒙板,邊框仍然會沿著圖層的邊界繪制出來掘猿。

陰影:shadowOpacity屬性取值在0.0(不可見)到1.0(完全不透明)之間病游,CGFloat類型〕硗ǎ可以改變?nèi)齻€相關(guān)屬性改變陰影的表現(xiàn):shadowColor衬衬,shadowOffsetshadowRadius改橘。
shadowOffsetCGSize滋尉,寬度控制橫向位移,高度控制縱向位移飞主,其默認(rèn)值為{0狮惜, -3}(陰影向上)。
shadowRadius控制陰影的模糊度碌识,CGFloat類型碾篡。當(dāng)它值為0(默認(rèn)值)時,陰影就有一個和視圖一樣有一個明確地邊界值筏餐,值越大邊界越模糊开泽,越接近自然陰影的效果。

和圖層邊框不同魁瞪,圖層的陰影繼承自內(nèi)容的外形穆律,而不是根據(jù)邊界和角半徑來確定。為了計算出陰影的形狀导俘,Core Animation會將寄宿圖(包括子視圖峦耘,如果有的話)考慮在內(nèi),然后通過這些來完美搭配圖層形狀從而創(chuàng)建一個陰影旅薄。

第一個雪人超出視圖邊界贡歧,陰影也是如此

但是CALayermaskToBounds屬性會把陰影也去掉:

?陰影被maskToBounds屬性去掉

如果想沿著內(nèi)容裁切,你需要用到兩個圖層:一個只畫陰影的空的外圖層赋秀,和一個用masksToBounds裁剪內(nèi)容的內(nèi)圖層。

?在原視圖底部添加一個畫陰影的圖層(即外圖層)
添加外圖層后的效果圖

我們已經(jīng)知道圖層陰影并不總是方的律想,而是從圖層內(nèi)容的形狀繼承而來猎莲。這看上去不錯,但是實時計算陰影也是一個非常消耗資源的技即,尤其是圖層有多個子圖層著洼,每個圖層還有一個有透明效果的寄宿圖的時候。

因此如果事先知道陰影形狀,可以使用shadowPath提高性能身笤,其類型為CGPathRef豹悬。
CGPath是一個Core Graphics對象,用來指定任意的一個矢量圖形液荸。我們可以通過這個屬性單獨于圖層形狀之外指定陰影的形狀瞻佛。

//enable layer shadows 
self.layerView1.layer.shadowOpacity = 0.5f; 
self.layerView2.layer.shadowOpacity = 0.5f;
 //create a square shadow CGMutablePathRef 
squarePath = CGPathCreateMutable(); 
CGPathAddRect(squarePath, NULL, self.layerView1.bounds); 
self.layerView1.layer.shadowPath = squarePath; 
 //create a circular shadow 
CGMutablePathRef circlePath = CGPathCreateMutable(); 
CGPathAddEllipseInRect(circlePath, NULL, self.layerView2.bounds); 
self.layerView2.layer.shadowPath = circlePath; 

效果圖

如果是一個矩形或者是圓,用CGPath會相當(dāng)簡單明了娇钱。但是如果是更加復(fù)雜一點的圖形伤柄,UIBezierPath類會更合適,它是一個由UIKit提供的在CGPath基礎(chǔ)上的Objective-C包裝類文搂。

圖層蒙板

CALayermask屬性适刀,其類型也是CALayer。有和其他圖層一樣的繪制和布局屬性煤蹭。它類似于一個子圖層笔喉,相對于父圖層布局,但是它卻不是一個普通的子圖層硝皂。不同于那些繪制在父圖層中的子圖層常挚,mask圖層定義了父圖層的部分可見區(qū)域。如果mask圖層比父圖層要小吧彪,只有在mask圖層里面的內(nèi)容才是它關(guān)心的待侵,除此以外的一切都會被隱藏起來。

下面用一個UIImageViewUIView的子類)演示一下:

??概念圖

UIImage *viewImage = [UIImage imageNamed:@"Igloo"];
    
//set mask
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = self.imageView.bounds;
UIImage *maskImage = [UIImage imageNamed:@"Cone.png"];
maskLayer.contents = (__bridge id)maskImage.CGImage;
    
self.imageView.image = viewImage;
self.imageView.layer.mask = maskLayer;
效果圖

CALayer蒙板圖層真正厲害的地方在于蒙板圖不局限于靜態(tài)圖姨裸。任何有圖層構(gòu)成的都可以作為mask屬性秧倾,這意味著你的蒙板可以通過代碼甚至是動畫實時生成。
</br>

拉伸過濾

</br>
總得來講傀缩,當(dāng)我們視圖顯示一個圖片的時候那先,都應(yīng)該正確地顯示這個圖片(意即:以正確的比例和正確的1:1像素顯示在屏幕上)赡艰。原因如下:

  • 能夠顯示最好的畫質(zhì)慷垮,像素既沒有被壓縮也沒有被拉伸揖闸。
  • 能更好的使用內(nèi)存,因為這就是所有你要存儲的東西汤纸。
  • 最好的性能表現(xiàn)芹血,CPU不需要為此額外的計算贮泞。

不過有時候楞慈,顯示一個非真實大小的圖片確實是我們需要的效果囊蓝。比如說一個頭像或是圖片的縮略圖令蛉,再比如說一個可以被拖拽和伸縮的大圖言询。這些情況下,為同一圖片的不同大小存儲不同的圖片顯得又不切實際夫啊。

當(dāng)圖片需要顯示不同的大小的時候撇眯,有一種叫做拉伸過濾的算法就起到作用了虱咧。它作用于原圖的像素上并根據(jù)需要生成新的像素顯示在屏幕上腕巡。

重繪圖片大小沒有一個統(tǒng)一的通用算法绘沉。這取決于需要拉伸的內(nèi)容,放大或是縮小的需求等這些因素车伞。CALayer為此提供了三種拉伸過濾方法:
(1)kCAFilterLinear
(2)kCAFilterNearest
(3)kCAFilterTrilinear

minification(縮小圖片)和magnification(放大圖片)默認(rèn)的過濾器都是kCAFilterLinear,這個過濾器采用雙線性濾波算法困曙,它在大多數(shù)情況下都表現(xiàn)良好慷丽。雙線性濾波算法通過對多個像素取樣最終生成新的值盈魁,得到一個平滑的表現(xiàn)不錯的拉伸窃诉。但是當(dāng)放大倍數(shù)比較大的時候圖片就模糊不清了飘痛。
kCAFilterTrilinearkCAFilterLinear非常相似宣脉,大部分情況下二者都看不出來有什么差別。但是塑猖,較雙線性濾波算法而言羊苟,三線性濾波算法存儲了多個大小情況下的圖片(也叫多重貼圖)蜡励,并三維取樣,同時結(jié)合大圖和小圖的存儲進(jìn)而得到最后的結(jié)果兼都。
這個方法的好處在于算法能夠從一系列已經(jīng)接近于最終大小的圖片中得到想要的結(jié)果扮碧,也就是說不要對很多像素同步取樣慎王。這不僅提高了性能柬祠,也避免了小概率因舍入錯誤引起的取樣失靈的問題负芋。對于大圖來說旧蛾,雙線性濾波和三線性濾波表現(xiàn)得更出色锨天。
kCAFilterNearest是一種比較武斷的方法病袄。從名字不難看出赘阀,這個算法(也叫最近過濾)就是取樣最近的單像素點而不管其他的顏色基公。這樣做非澈涠梗快酸休,也不會使圖片模糊祷杈。但是吠式,最明顯的效果就是特占,會使得壓縮圖片更糟是目,圖片放大之后也顯得塊狀或是馬賽克嚴(yán)重。對于沒有斜線的小圖來說揉抵,最近過濾算法要好很多冤今。

三者對比圖
?三者對比圖

總的來說,對于比較小的圖或者是差異特別明顯脚囊,極少斜線的大圖悔耘,最近過濾算法會保留這種差異明顯的特質(zhì)以呈現(xiàn)更好的結(jié)果。但是對于大多數(shù)的圖尤其是有很多斜線或是曲線輪廓的圖片來說校摩,最近過濾算法會導(dǎo)致更差的結(jié)果秧耗。換句話說,線性過濾保留了形狀霉猛,最近過濾則保留了像素的差異珠闰。

拉伸實驗伏嗜,使用一個1x的圖片顯示:

1x數(shù)字圖

magification - kCAFilterLinear

magification - kCAFilterNearest

</br>
####組透明

iOS常見的做法是把一個空間的alpha值設(shè)置為0.5(50%)以使其看上去呈現(xiàn)為不可用狀態(tài)裸影。對于獨立的視圖來說還不錯轩猩,但是當(dāng)一個控件有子視圖的時候就有點奇怪了均践,例如一個內(nèi)嵌了UILabel的自定義UIButton:

Paste_Image.png

左邊是一個不透明的按鈕彤委,右邊是50%透明度的相同按鈕焦影。我們可以注意到薇宠,里面的標(biāo)簽的輪廓跟按鈕的背景很不搭調(diào)澄港。

這是由透明度的混合疊加造成的回梧,當(dāng)你顯示一個50%透明度的圖層時,圖層的每個像素都會一般顯示自己的顏色拯欧,另一半顯示圖層下面的顏色镐作。這是正常的透明度的表現(xiàn)隆箩。但是如果圖層包含一個同樣顯示50%透明的子圖層時捌臊,你所看到的視圖理澎,50%來自子視圖糠爬,25%來自圖層本身的顏色秩铆,另外的25%則來自背景色。

可以設(shè)置CALayer的一個叫做shouldRasterize
屬性來實現(xiàn)組透明的效果捅膘,如果它被設(shè)置為YES寻仗,在應(yīng)用透明度之前署尤,圖層及其子圖層都會被整合成一個整體的圖片曹体,這樣就沒有透明度混合的問題了箕别。
為了啟用shouldRasterize屬性串稀,我們設(shè)置了圖層的rasterizationScale屬性母截。默認(rèn)情況下清寇,所有圖層拉伸都是1.0, 所以如果你使用了shouldRasterize屬性陷遮,你就要確保你設(shè)置了rasterizationScale屬性去匹配屏幕,以防止出現(xiàn)Retina屏幕像素化的問題比吭。

</br>

Chapter 5

</br>
第三章中UIViewtransform屬性是一個CGAffineTransform類型衩藤,用于在二維空間做旋轉(zhuǎn)赏表,縮放和平移瓢剿。CGAffineTransform是一個可以和二維空間向量(例如CGPoint)做乘法的3X2的矩陣:

用矩陣表示CGPoint和CGAffineTransform

式中用CGPoint的每一列和CGAffineTransform矩陣的每一行對應(yīng)元素相乘再求和间狂,就形成了一個新的CGPoint類型的結(jié)果鉴象。要解釋一下圖中顯示的灰色元素纺弊,為了能讓矩陣做乘法淆游,左邊矩陣的列數(shù)一定要和右邊矩陣的行數(shù)個數(shù)相同稽犁,所以要給矩陣填充一些標(biāo)志值已亥,使得既可以讓矩陣做乘法虑椎,又不改變運算結(jié)果捆姜,并且沒必要存儲這些添加的值泥技,因為它們的值不會發(fā)生變化珊豹,但是要用來做運算店茶。

因此贩幻,通常會用3×3(而不是2×3)的矩陣來做二維變換丛楚,你可能會見到3行2列格式的矩陣趣些,這是所謂的以列為主的格式喧务,上圖所示的是以行為主的格式,只要能保持一致庐冯,用哪種格式都無所謂展父。

當(dāng)對圖層應(yīng)用變換矩陣栖茉,圖層矩形內(nèi)的每一個點都被相應(yīng)地做變換吕漂,從而形成一個新的四邊形的形狀惶凝。CGAffineTransform中的“仿射”的意思是無論變換矩陣用什么值苍鲜,圖層中平行的兩條線在變換之后任然保持平行混滔,CGAffineTransform可以做出任意符合上述標(biāo)注的變換坯屿,?下圖顯示了一些仿射的和非仿射的變換:

仿射和非仿射

UIView可以通過設(shè)置transform屬性做變換,但實際上它只是封裝了內(nèi)部圖層的變換隔节。

CALayer同樣也有一個transform屬性怎诫,但它的類型是CATransform3D幻妓,而不是CGAffineTransform肉津,本章后續(xù)將會詳細(xì)解釋妹沙。CALayer對應(yīng)于UIViewtransform屬性叫做affineTransform距糖。
</br>

旋轉(zhuǎn)

</br>
使用CALayeraffineTransform屬性把一個圖片旋轉(zhuǎn)45°:

CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_4);
    
self.layerView.layer.affineTransform = transform;

效果圖

注意我們使用的旋轉(zhuǎn)常量是M_PI_4恩脂,而不是你想象的45俩块,因為iOS的變換函數(shù)使用弧度而不是角度作為單位典阵∽嘲。弧度用數(shù)學(xué)常量pi的倍數(shù)表示歹啼,一個pi代表180°狸眼,所以四分之一的pi就是45°拓萌。
C的數(shù)學(xué)函數(shù)庫(iOS會自動引入)提供了pi的一些簡便的換算,M_PI_4于是就是pi的四分之一

</br>

混合變換

</br>
Core Graphics提供了一系列的函數(shù)可以在一個變換的基礎(chǔ)上做更深層次的變換

CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy) 
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)

當(dāng)操縱一個變換的時候炕倘,初始生成一個什么都不做的變換很重要--也就是創(chuàng)建一個CGAffineTransform類型的空值罩旋,矩陣論中稱作單位矩陣涨醋,Core Graphics同樣也提供了一個方便的常量:

CGAffineTransformIdentity

最后东帅,如果需要混合兩個已經(jīng)存在的變換矩陣靠闭,就可以使用如下方法愧膀,在兩個變換的基礎(chǔ)上創(chuàng)建一個新的變換:

CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末芬为,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蟀悦,更是在濱河造成了極大的恐慌媚朦,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件日戈,死亡現(xiàn)場離奇詭異询张,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)浙炼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弯屈,“玉大人蜗帜,你說我怎么就攤上這事∽世鳎” “怎么了厅缺?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宴偿。 經(jīng)常有香客問我湘捎,道長,這世上最難降的妖魔是什么酪我? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮且叁,結(jié)果婚禮上都哭,老公的妹妹穿的比我還像新娘。我一直安慰自己逞带,他們只是感情好欺矫,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著展氓,像睡著了一般穆趴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上遇汞,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天未妹,我揣著相機(jī)與錄音簿废,去河邊找鬼。 笑死络它,一個胖子當(dāng)著我的面吹牛族檬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播化戳,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼单料,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了点楼?” 一聲冷哼從身側(cè)響起扫尖,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎掠廓,沒想到半個月后换怖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡却盘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年狰域,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片黄橘。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡兆览,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出塞关,到底是詐尸還是另有隱情抬探,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布帆赢,位于F島的核電站小压,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏椰于。R本人自食惡果不足惜怠益,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瘾婿。 院中可真熱鬧蜻牢,春花似錦、人聲如沸偏陪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笛谦。三九已至抱虐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饥脑,已是汗流浹背恳邀。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工懦冰, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人轩娶。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓儿奶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鳄抒。 傳聞我的和親對象是個殘疾皇子闯捎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容