轉(zhuǎn)載:http://www.cnblogs.com/jingdizhiwa/p/5601240.html
1.geometryFlipped設(shè)置為yes,則子圖層或者子視圖本來相對于左上角放置 改為 相對于左下角放置捧挺;
2.contents
3.contentGravity:
kCAGravityCenter
kCAGravityTop
kCAGravityBottom
kCAGravityLeft
kCAGravityRight
kCAGravityTopLeft
kCAGravityTopRight
kCAGravityBottomLeft
kCAGravityBottomRight
kCAGravityResize
kCAGravityResizeAspect
kCAGravityResizeAspectFill
4.contentsScale
5.maskToBounds
6.contentsRect
7.contentsCenter
8.自己繪制寄宿圖:
方法-:繼承UIView并實現(xiàn)-drawRect:(如果你不需要寄宿圖停局,那就不要創(chuàng)建這個方法了,這會造成CPU資源和內(nèi)存的浪費,這也是為什么蘋果建議:如果沒有自定義繪制的任務(wù)就不要在子類中寫一個空的-drawRect:方法狈茉。)
方法二:CALayer有一個可選的delegate屬性,參考代碼如下:
blueLayer.delegate=self;
[blueLayer display];- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{//draw a thick red circleCGContextSetLineWidth(ctx,10.0f);
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextStrokeEllipseInRect(ctx, layer.bounds);
}
我們在blueLayer上顯式地調(diào)用了-display掸掸。不同于UIView氯庆,當圖層顯示在屏幕上時,CALayer不會自動重繪它的內(nèi)容扰付。它把重繪的決定權(quán)交給了開發(fā)者堤撵。
盡管我們沒有用masksToBounds屬性,繪制的那個圓仍然沿邊界被裁剪了羽莺。這是因為當你使用CALayerDelegate繪制寄宿圖的時候实昨,并沒有對超出邊界外的內(nèi)容提供繪制支持。
9.布局:
frame并不是一個非常清晰的屬性禽翼,它其實是一個虛擬屬性屠橄,是根據(jù)bounds,position和transform計算而來闰挡,所以當其中任何一個值發(fā)生改變,frame都會變化礁哄。相反长酗,改變frame的值同樣會影響到他們當中的值;
錨點:
10.坐標系:
- (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;
11.zPosition
增加圖層的zPosition桐绒,就可以把圖層向相機方向前置夺脾,于是它就在所有其他圖層的前面了(或者至少是小于它的zPosition值的圖層的前面);同樣適用于視圖的layer
12.Hit Testing
CALayer并不關(guān)心任何響應(yīng)鏈事件之拨,所以不能直接處理觸摸事件或者手勢。但是它有一系列的方法幫你處理事件:-containsPoint:和-hitTest:咧叭。
13.自動布局
如果想隨意控制CALayer的布局蚀乔,就需要手工操作。最簡單的方法就是使用CALayerDelegate如下函數(shù):
-?(void)layoutSublayersOfLayer:(CALayer?*)layer;
當圖層的bounds發(fā)生改變菲茬,或者圖層的-setNeedsLayout方法被調(diào)用的時候吉挣,這個函數(shù)將會被執(zhí)行。這使得你可以手動地重新擺放或者重新調(diào) 整子圖層的大小婉弹,但是不能像UIView的autoresizingMask和constraints屬性做到自適應(yīng)屏幕旋轉(zhuǎn)睬魂。
14.conrnerRadius
默認情況下,這個曲率值只影響背景顏色而不影響背景圖片或是子圖層镀赌。不過氯哮,如果把masksToBounds設(shè)置成YES的話,圖層里面的所有東西都會被截取
15.shadowOpacity
若要改動陰影的表現(xiàn)商佛,你可以使用CALayer的另外三個屬性:shadowColor喉钢,shadowOffset和shadowRadius
16.shadowPath屬性
我們已經(jīng)知道圖層陰影并不總是方的,而是從圖層內(nèi)容的形狀繼承而來良姆。這看上去不錯肠虽,但是實時計算陰影也是一個非常消耗資源的,尤其是圖層有多個子圖層歇盼,每個圖層還有一個有透明效果的寄宿圖的時候舔痕。
如果你事先知道你的陰影形狀會是什么樣子的,你可以通過指定一個shadowPath來提高性能;
17.圖層蒙板
@interfaceViewController ()
@property (nonatomic, weak) IBOutlet UIImageView*imageView;@end@implementationViewController- (void)viewDidLoad
{
[super viewDidLoad];//create mask layerCALayer*maskLayer =[CALayer layer];
maskLayer.frame=self.imageView.bounds;
UIImage*maskImage = [UIImage imageNamed:@"1"];
maskLayer.contents= (__bridgeid)maskImage.CGImage;//apply mask to image layer?self.imageView.layer.mask=maskLayer;
self.imageView.image=[UIImage imageNamed:@"2"];
}@end
CALayer蒙板圖層真正厲害的地方在于蒙板圖不局限于靜態(tài)圖豹缀。任何有圖層構(gòu)成的都可以作為mask屬性伯复,這意味著你的蒙板可以通過代碼甚至是動畫實時生成。
18.shouldRasterize
實現(xiàn)組透明的效果邢笙,如果它被設(shè)置為YES啸如,在應(yīng)用透明度之前,圖層及其子圖層都會被整合成一個整體的圖片氮惯,這樣就沒有透明度混合的問題了;
為了啟用shouldRasterize屬性叮雳,我們設(shè)置了圖層的rasterizationScale屬性。默認情況下妇汗,所有圖層拉伸都是1.0帘不, 所以如果你使用了shouldRasterize屬性,你就要確保你設(shè)置了rasterizationScale屬性去匹配屏幕杨箭,以防止出現(xiàn)Retina屏幕像素化的問題寞焙。
button2.layer.shouldRasterize =YES;
button2.layer.rasterizationScale= [UIScreen mainScreen].scale;
19.變換(CGAffineTransform)
view.transform=CGAffineTransformMakeRotation(M_PI_4) <---->self.view.layer.affineTransform=CGAffineTransformMakeRotation(M_PI_4) ;
CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
混合變換
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
參考代碼:
CGAffineTransform transform = CGAffineTransformIdentity;//scale by 50%transform = CGAffineTransformScale(transform,0.5,0.5);//rotate by 30 degreestransform = CGAffineTransformRotate(transform, M_PI /180.0*30.0);//translate by 200 pointstransform = CGAffineTransformTranslate(transform,200,0);//apply transform to layerself.layerView.layer.affineTransform = transform;
設(shè)置CGAffineTransform的矩陣值,做任意變換:
CGAffineTransform transform =CGAffineTransformIdentity;
transform.c= -x;
transform.b= y;
20.變換(CATransform3D)
對應(yīng)layer的transform屬性
CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz)
CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)
transform.m34---->應(yīng)用透視效果
21.sublayerTransform
CALayer有一個屬性叫做sublayerTransform。它也是CATransform3D類型捣郊,但和對一個圖層的變換不同辽狈,它影響到所有的子圖層。這意味著你可以一次性對包含這些圖層的容器做變換呛牲,于是所有的子圖層都自動繼承了這個變換方法刮萌。
22.doubleSided
CALayer有一個叫做doubleSided的屬性來控制圖層的背面是否要被繪制。這是一個BOOL類型娘扩,默認為YES着茸,如果設(shè)置為NO,那么當圖層正面從相機視角消失的時候畜侦,它將不會被繪制元扔。
23.CAShapeLayer
使用CAShapeLayer有以下一些優(yōu)點:
渲染快速。CAShapeLayer使用了硬件加速旋膳,繪制同一圖形會比用Core Graphics快很多澎语。
高效使用內(nèi)存。一個CAShapeLayer不需要像普通CALayer一樣創(chuàng)建一個寄宿圖形验懊,所以無論有多大擅羞,都不會占用太多的內(nèi)存。
不會被圖層邊界剪裁掉义图。一個CAShapeLayer可以在邊界之外繪制减俏。你的圖層路徑不會像在使用Core Graphics的普通CALayer一樣被剪裁掉(如我們在第二章所見)。
不會出現(xiàn)像素化碱工。當你給CAShapeLayer做3D變換時娃承,它不像一個有寄宿圖的普通圖層一樣變得像素化。
24.CATextLayer
CATextLayer比UILabel有著更好的性能表現(xiàn)怕篷,同時還有額外的布局選項并且在iOS 5上支持富文本历筝。
讓我們編輯一下示例使用到NSAttributedString(見清單6.3).iOS 6及以上我們可以用新的NSTextAttributeName實例來設(shè)置我們的字符串屬性,但是練習的目的是為了演示在iOS 5及以下廊谓,所以我們用了Core Text梳猪,也就是說你需要把Core Text framework添加到你的項目中。否則蒸痹,編譯器是無法識別屬性常量的春弥。
UILabel的替代品
每一個UIView都是寄宿在一個CALayer的示例上。這個圖層是由視圖自動創(chuàng)建和管理的叠荠,那我們可以用別的圖層類型替代它么匿沛?一旦被創(chuàng)建,我們就無法代替這個圖層了榛鼎。但是如果我們繼承了UIView俺祠,那我們就可以重寫+layerClass方法使得在創(chuàng)建的時候能返回一個不同的圖層子類公给。UIView會在初始化的時候調(diào)用+layerClass方法借帘,然后用它的返回類型來創(chuàng)建宿主圖層蜘渣。
把CATextLayer作為宿主圖層的另一好處就是視圖自動設(shè)置了contentsScale屬性。
25.CATransformLayer
在立方體示例肺然,我們將通過旋轉(zhuǎn)camara來解決圖層平面化問題而不是像立方體示例代碼中用的sublayerTransform蔫缸。這是一個非常不錯的技巧,但是只能作用域單個對象上际起,如果你的場景包含兩個立方體拾碌,那我們就不能用這個技巧單獨旋轉(zhuǎn)他們了。
CATransformLayer不同于普通的CALayer街望,因為它不能顯示它自己的內(nèi)容校翔。只有當存在了一個能作用域子圖層的變換它才真正存在。CATransformLayer并不平面化它的子圖層灾前,所以它能夠用于構(gòu)造一個層級的3D結(jié)構(gòu)防症。
26.CAGradientLayer
CAGradientLayer是用來生成兩種或更多顏色平滑漸變的。用Core Graphics復制一個CAGradientLayer并將內(nèi)容繪制到一個普通圖層的寄宿圖也是有可能的哎甲,但是CAGradientLayer的真正好處在于繪制使用了硬件加速蔫敲。
27.CAReplicatorLayer
CAReplicatorLayer的目的是為了高效生成許多相似的圖層。它會繪制一個或多個圖層的子圖層炭玫,并在每個復制體上應(yīng)用不同的變換奈嘿。
instanceCount屬性指定了圖層需要重復多少次。instanceTransform指定了一個CATransform3D 3D變換(這種情況下吞加,下一圖層的位移和旋轉(zhuǎn)將會移動到圓圈的下一個點)裙犹。變換是逐步增加的,每個實例都是相對于前一實例布局衔憨。這就是為什么這些復制體最終不會出現(xiàn)在同一位置上叶圃;
CAReplicatorLayer真正應(yīng)用到實際程序上的場景比如:一個游戲中導彈的軌跡云,或者粒子爆炸巫财。除此之外盗似,還有一個實際應(yīng)用是:反射。
28.CAScrollLayer
CAScrollLayer有一個-scrollToPoint:方法平项,它自動適應(yīng)bounds的原點以便圖層內(nèi)容出現(xiàn)在滑動的地方赫舒。注意,這就是它做的所有事情闽瓢。前面提到過接癌,Core Animation并不處理用戶輸入,所以CAScrollLayer并不負責將觸摸事件轉(zhuǎn)換為滑動事件扣讼,既不渲染滾動條缺猛,也不實現(xiàn)任何iOS指定行為例如滑動反彈(當視圖滑動超多了它的邊界的將會反彈回正確的地方)。
1.CATransaction
事務(wù);
UIView有兩個方法荔燎,+beginAnimations:context:和+commitAnimations耻姥,和CATransaction的+begin 和+commit方法類似。實際上在+beginAnimations:context:和+commitAnimations之間所有視圖或者圖層屬性的改變而做的動畫都是由于設(shè)置了CATransaction的原因有咨。
UIView封裝動畫中的塊動畫琐簇,對做一堆的屬性動畫在語法上會更加簡單,但實質(zhì)上它們都是在做同樣的事情座享。
基于UIView的block的動畫允許你在動畫結(jié)束的時候提供一個完成的動作婉商。CATranscation接口提供的+setCompletionBlock:方法也有同樣的功能
2.屬性動畫實質(zhì):
當CALayer的屬性被修改時候渤早,它會調(diào)用-actionForKey:方法繁莹,傳遞屬性的名稱。剩下的操作都在CALayer的頭文件中有詳細的說明烁巫,實質(zhì)上是如下幾步:
圖層首先檢測它是否有委托淳衙,并且是否實現(xiàn)CALayerDelegate協(xié)議指定的-actionForLayer:forKey方法蘑秽。如果有,直接調(diào)用并返回結(jié)果滤祖。
如果沒有委托筷狼,或者委托沒有實現(xiàn)-actionForLayer:forKey方法,圖層接著檢查包含屬性名稱對應(yīng)行為映射的actions字典匠童。
如果actions字典沒有包含對應(yīng)的屬性埂材,那么圖層接著在它的style字典接著搜索屬性名。
最后汤求,如果在style里面也找不到對應(yīng)的行為俏险,那么圖層將會直接調(diào)用定義了每個屬性的標準行為的-defaultActionForKey:方法。
所以一輪完整的搜索結(jié)束之后扬绪,-actionForKey:要么返回空(這種情況下將不會有動畫發(fā)生)竖独,要么是CAAction協(xié)議對應(yīng)的對象,最后CALayer拿這個結(jié)果去對先前和當前的值做動畫挤牛。
通過下面一段代碼莹痢,可以理解每個UIView對它關(guān)聯(lián)的圖層是如何禁用隱式動畫的
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"Outside: %@", [self.view actionForLayer:self.view.layer forKey:@"backgroundColor"]);
[UIView beginAnimations:nil context:nil];
NSLog(@"Inside: %@", [self.view actionForLayer:self.view.layer forKey:@"backgroundColor"]);
[UIView commitAnimations];
}
運行結(jié)果:
2016-05-3014:48:18.614測試[10222:147396] Outside: 2016-05-3014:48:18.615測試[10222:147396] Inside:
總結(jié)一下,我們知道了如下幾點
UIView 關(guān)聯(lián)的圖層禁用了隱式動畫墓赴,對這種圖層做動畫的唯一辦法就是使用UIView的動畫函數(shù)(而不是依賴CATransaction)竞膳,或者繼承 UIView,并覆蓋-actionForLayer:forKey:方法诫硕,或者直接創(chuàng)建一個顯式動畫(具體細節(jié)見第八章)坦辟。
對于單獨存在的圖層,我們可以通過實現(xiàn)圖層的-actionForLayer:forKey:委托方法章办,或者提供一個actions字典來控制隱式動畫锉走。
3.CATransition
CATransition繼承CAAnimation滨彻,而CAAnimation響應(yīng)CAAction協(xié)議;
CATransition *transition =[CATransition animation];
transition.type=kCATransitionPush;
transition.subtype=kCATransitionFromLeft;
self.colorLayer.actions= @{@"backgroundColor": transition};
這種方法,只是針對單獨的圖層挪蹭,不能用在UIView關(guān)聯(lián)的圖層亭饵;
4.presentationLayer
每個圖層屬性的顯示值都被存儲在一個叫做呈現(xiàn)圖層的獨立圖層當中,他可以通過-presentationLayer方法來訪問嚣潜。這個呈現(xiàn)圖層實際上是模型圖層的復制冬骚,但是它的屬性值代表了在任何指定時刻當前外觀效果。換句話說懂算,你可以通過呈現(xiàn)圖層的值來獲取當前屏幕上真正顯示出來的值
注意呈現(xiàn)圖層僅僅當圖層首次被提交(就是首次第一次在屏幕上顯示)的時候創(chuàng)建,所以在那之前調(diào)用-presentationLayer將會返回nil庇麦。
在呈現(xiàn)圖層上調(diào)用–modelLayer將會返回它正在呈現(xiàn)所依賴的CALayer计技。通常在一個圖層上調(diào)用-modelLayer會返回–self(實際上我們已經(jīng)創(chuàng)建的原始圖層就是一種數(shù)據(jù)模型)。
5.顯式動畫
在iOS中核心動畫分為幾類:基礎(chǔ)動畫山橄、關(guān)鍵幀動畫垮媒、動畫組、轉(zhuǎn)場動畫航棱。各個類的關(guān)系大致如下:
CAAnimation:核心動畫的基礎(chǔ)類睡雇,不能直接使用,負責動畫運行時間饮醇、速度的控制它抱。CAAnimation本身并沒有做多少工作,它提供了一個計時函數(shù)朴艰,一個委托(用于反饋動畫狀態(tài))以及一個 removedOnCompletion观蓄,用于標識動畫是否該在結(jié)束后自動釋放(默認YES,為了防止內(nèi)存泄露)祠墅。CAAnimation同時實現(xiàn)了一些 協(xié)議侮穿,包括CAAction(允許CAAnimation的子類可以提供圖層行為),以及CAMediaTiming
CAPropertyAnimation:屬性動畫的基類(通過屬性進行動畫設(shè)置毁嗦,注意是可動畫屬性)亲茅,不能直接使用。通過指定動畫的keyPath作用于一個單一屬性狗准,CAAnimation通常應(yīng)用于一個指定的CALayer克锣,于是這里指的也就是一個圖層的 keyPath了。實際上它是一個關(guān)鍵路徑(一些用點表示法可以在層級關(guān)系中指向任意嵌套的對象)驶俊,而不僅僅是一個屬性的名稱娶耍,因為這意味著動畫不僅可以 作用于圖層本身的屬性,而且還包含了它的子成員的屬性饼酿,甚至是一些虛擬的屬性
CAAnimationGroup:動畫組榕酒,動畫組是一種組合模式設(shè)計胚膊,可以通過動畫組來進行所有動畫行為的統(tǒng)一控制,組中所有動畫效果可以并發(fā)執(zhí)行想鹰。
CATransition:過渡(轉(zhuǎn)場)動畫紊婉,主要通過濾鏡進行動畫效果設(shè)置。過渡并不像屬性動畫那樣平滑地在兩個值之間做動畫辑舷,而是影響到整個圖層的變化喻犁。過渡動畫首先展示之前的圖層外觀,然后通過一個交換過渡到新的外觀何缓。
CABasicAnimation:基礎(chǔ)動畫肢础,通過屬性修改進行動畫參數(shù)控制,只有初始狀態(tài)和結(jié)束狀態(tài)碌廓。
CAKeyframeAnimation:關(guān)鍵幀動畫传轰,同樣是通過屬性進行動畫參數(shù)控制,但是同基礎(chǔ)動畫不同的是它可以有多個狀態(tài)控制谷婆。CAKeyFrameAnimation添加了一個rotationMode的屬性慨蛙。設(shè)置它為常量kCAAnimationRotateAuto,圖層將會根據(jù)曲線的切線自動旋轉(zhuǎn)
基礎(chǔ)動畫纪挎、關(guān)鍵幀動畫都屬于屬性動畫期贫,就是通過修改屬性值產(chǎn)生動畫效果,開發(fā)人員只需要設(shè)置初始值和結(jié)束值异袄,中間的過程動畫(又叫“補間動畫”)由 系統(tǒng)自動計算產(chǎn)生通砍。和基礎(chǔ)動畫不同的是關(guān)鍵幀動畫可以設(shè)置多個屬性值,每兩個屬性中間的補間動畫由系統(tǒng)自動完成隙轻,因此從這個角度而言基礎(chǔ)動畫又可以看成是 有兩個關(guān)鍵幀的關(guān)鍵幀動畫埠帕。
- (void)applyBasicAnimation:(CABasicAnimation *)animation toLayer:(CALayer *)layer
{//set the from value (using presentation layer if available)animation.fromValue = [layer.presentationLayer ?: layer valueForKeyPath:animation.keyPath];//update the property in advance//note: this approach will only work if toValue != nil[CATransaction begin];
[CATransaction setDisableActions:YES];
[layer setValue:animation.toValue forKeyPath:animation.keyPath];
[CATransaction commit];//apply animation to layer[layer addAnimation:animation forKey:nil];
}-(IBAction)changeColor
{//create a new random colorCGFloat red = arc4random() /(CGFloat)INT_MAX;
CGFloat green= arc4random() /(CGFloat)INT_MAX;
CGFloat blue= arc4random() /(CGFloat)INT_MAX;
UIColor*color = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];//create a basic animationCABasicAnimation *animation =[CABasicAnimation animation];
animation.keyPath=@"backgroundColor";
animation.toValue= (__bridgeid)color.CGColor;//apply animation without snap-back[self applyBasicAnimation:animation toLayer:self.colorLayer];
}
6.虛擬屬性
CABasicAnimation *animation =[CABasicAnimation animation];
animation.keyPath=@"transform.rotation";
animation.duration=2.0;
animation.byValue= @(M_PI *2);
[shipLayer addAnimation:animation forKey:nil];
用transform.rotation而不是transform做動畫的好處如下:
我們可以不通過關(guān)鍵幀一步旋轉(zhuǎn)多于180度的動畫。
可以用相對值而不是絕對值旋轉(zhuǎn)(設(shè)置byValue而不是toValue)玖绿。
可以不用創(chuàng)建CATransform3D敛瓷,而是使用一個簡單的數(shù)值來指定角度。
不會和transform.position或者transform.scale沖突(同樣是使用關(guān)鍵路徑來做獨立的動畫屬性)斑匪。
transform.rotation 屬性有一個奇怪的問題是它其實并不存在呐籽。這是因為CATransform3D并不是一個對象,它實際上是一個結(jié)構(gòu)體蚀瘸,也沒有符合KVC相關(guān)屬 性狡蝶,transform.rotation實際上是一個CALayer用于處理動畫變換的虛擬屬性。
7.動畫組
//create group animationCAAnimationGroup *groupAnimation =[CAAnimationGroup animation];
groupAnimation.animations=@[animation1, animation2];
groupAnimation.duration=4.0;//add the animation to the color layer[colorLayer addAnimation:groupAnimation forKey:nil];
8.過渡動畫
CAAnimation有一個type和subtype來標識變換效果贮勃。type屬性是一個NSString類型贪惹,可以被設(shè)置成如下類型:
kCATransitionFade
kCATransitionMoveIn
kCATransitionPush
kCATransitionReveal
通過subtype來控制它們的方向,提供了如下四種類型:
kCATransitionFromRight
kCATransitionFromLeft
kCATransitionFromTop
kCATransitionFromBottom
隱式過渡
CATransision 可以對圖層任何變化平滑過渡的事實使得它成為那些不好做動畫的屬性圖層行為的理想候選寂嘉。蘋果當然意識到了這點奏瞬,并且當設(shè)置了CALayer的 content屬性的時候枫绅,CATransition的確是默認的行為。但是對于視圖關(guān)聯(lián)的圖層硼端,或者是其他隱式動畫的行為并淋,這個特性依然是被禁用的,但 是對于你自己創(chuàng)建的圖層珍昨,這意味著對圖層contents圖片做的改動都會自動附上淡入淡出的動畫县耽。
對圖層樹的動畫
CATransition并不作用于指定的圖層屬性,這就是說你可以在即使不能準確得知改變了什么的情況下對圖層做動畫镣典,例如兔毙,在不知道 UITableView哪一行被添加或者刪除的情況下,直接就可以平滑地刷新它骆撇,或者在不知道UIViewController內(nèi)部的視圖層級的情況下對 兩個不同的實例做過渡動畫瞒御。
這些例子和我們之前所討論的情況完全不同,因為它們不涉及到圖層的屬性神郊,而且是整個圖層樹的改變--我們在這種動畫的過程中手動在層級關(guān)系中添加或者移除圖層。
這里用到了一個小詭計趾唱,要確保CATransition添加到的圖層在過渡動畫發(fā)生時不會在樹狀結(jié)構(gòu)中被移除涌乳,否則CATransition將會和圖層一起被移除。一般來說甜癞,你只需要將動畫添加到被影響圖層的superlayer夕晓。
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{//set up crossfade transitionCATransition *transition =[CATransition animation];
transition.type=kCATransitionFade;//apply transition to tab bar controller's view[self.tabBarController.view.layer addAnimation:transition forKey:nil];
}
自定義動畫
奇怪的是蘋果通過UIView +transitionFromView:toView:duration:options:completion: 和+transitionWithView:duration:options:animations:方法提供了Core Animation的過渡特性。但是這里的可用的過渡選項和CATransition的type屬性提供的常量完全不同悠咱。UIView過渡方法中 options參數(shù)可以由如下常量指定:
UIViewAnimationOptionTransitionFlipFromLeft
UIViewAnimationOptionTransitionFlipFromRight
UIViewAnimationOptionTransitionCurlUp
UIViewAnimationOptionTransitionCurlDown
UIViewAnimationOptionTransitionCrossDissolve
UIViewAnimationOptionTransitionFlipFromTop
UIViewAnimationOptionTransitionFlipFromBottom
過渡動畫做基礎(chǔ)的原則就是對原始的圖層外觀截圖蒸辆,然后添加一段動畫,平滑過渡到圖層改變之后那個截圖的效果析既。如果我們知道如何對圖層截圖躬贡,我們就可以使用屬性動畫來代替CATransition或者是UIKit的過渡方法來實現(xiàn)動畫。
事實證明眼坏,對圖層做截圖還是很簡單的拂玻。CALayer有一個-renderInContext:方法,可以通過把它繪制到Core Graphics的上下文中捕獲當前內(nèi)容的圖片宰译,然后在另外的視圖中顯示出來檐蚜。如果我們把這個截屏視圖置于原始視圖之上,就可以遮住真實視圖的所有變化沿侈, 于是重新創(chuàng)建了一個簡單的過渡效果闯第。
清單8.14演示了一個基本的實現(xiàn)。我們對當前視圖狀態(tài)截圖缀拭,然后在我們改變原始視圖的背景色的時候?qū)貓D快速轉(zhuǎn)動并且淡出咳短,圖8.5展示了我們自定義的過渡效果填帽。
為 了讓事情更簡單,我們用UIView -animateWithDuration:completion:方法來實現(xiàn)诲泌。雖然用CABasicAnimation可以達到同樣的效果盲赊,但是那樣的 話我們就需要對圖層的變換和不透明屬性創(chuàng)建單獨的動畫,然后當動畫結(jié)束的是哦戶在CAAnimationDelegate中把coverView從屏幕中 移除敷扫。
清單8.14 用renderInContext:創(chuàng)建自定義過渡效果
-(IBAction)performTransition
{//preserve the current view snapshotUIGraphicsBeginImageContextWithOptions(self.view.bounds.size, YES,0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage*coverImage =UIGraphicsGetImageFromCurrentImageContext();//insert snapshot view in front of this oneUIView *coverView =[[UIImageView alloc] initWithImage:coverImage];
coverView.frame=self.view.bounds;
[self.view addSubview:coverView];//update the view (we'll simply randomize the layer background color)CGFloat red = arc4random() /(CGFloat)INT_MAX;
CGFloat green= arc4random() /(CGFloat)INT_MAX;
CGFloat blue= arc4random() /(CGFloat)INT_MAX;
self.view.backgroundColor= [UIColor colorWithRed:red green:green blue:blue alpha:1.0];//perform animation (anything you like)[UIView animateWithDuration:1.0animations:^{//scale, rotate and fade the viewCGAffineTransform transform = CGAffineTransformMakeScale(0.01,0.01);
transform=CGAffineTransformRotate(transform, M_PI_2);
coverView.transform=transform;
coverView.alpha=0.0;
} completion:^(BOOL finished) {//remove the cover view now we're finished with it[coverView removeFromSuperview];
}];
}
CAMediaTiming協(xié)議
duration
repeatCount
repeatDuration
autoreverses
注意repeatCount和repeatDuration可能會相互沖突哀蘑,所以你只要對其中一個指定非零值。對兩個屬性都設(shè)置非0值的行為沒有被定義葵第。
beginTime
指定了動畫開始之前的的延遲時間绘迁。這里的延遲從動畫添加到可見圖層的那一刻開始測量,默認是0(就是說動畫會立刻執(zhí)行)卒密。
speed
是一個時間的倍數(shù)缀台,默認1.0,減少它會減慢圖層/動畫的時間哮奇,增加它會加快速度膛腐。如果2.0的速度,那么對于一個duration為1的動畫鼎俘,實際上在0.5秒的時候就已經(jīng)完成了哲身。
timeOffset
和beginTime類似,但是和增加beginTime導致的延遲動畫不同贸伐,增加timeOffset只是讓動畫快進到某一點勘天,例如,對于一個持續(xù)1秒的動畫來說捉邢,設(shè)置timeOffset為0.5意味著動畫將從一半的地方開始脯丝。
fillMode
fillMode是一個NSString類型,可以接受如下四種常量:
kCAFillModeForwards
kCAFillModeBackwards
kCAFillModeBoth
kCAFillModeRemoved
默認是kCAFillModeRemoved伏伐,當動畫不再播放的時候就顯示圖層模型指定的值剩下的三種類型向前宠进,向后或者即向前又向后去填充動畫狀態(tài),使得動畫在開始前或者結(jié)束后仍然保持開始和結(jié)束那一刻的值秘案。
這就對避免在動畫結(jié)束的時候急速返回提供另一種方案(見第八章)砰苍。但是記住了,當用它來解決這個問題的時候阱高,需要把removeOnCompletion設(shè)置為NO赚导,另外需要給動畫添加一個非空的鍵,于是可以在不需要動畫的時候把它從圖層上移除赤惊。
暫停吼旧,倒回和快進(圖層的speed)
設(shè)置動畫的speed屬性為0可以暫停動畫,但在動畫被添加到圖層之后不太可能再修改它了未舟,所以不能對正在進行的動畫使用這個屬性圈暗。給圖層添加一個 CAAnimation實際上是給動畫對象做了一個不可改變的拷貝掂为,所以對原始動畫對象屬性的改變對真實的動畫并沒有作用。相反员串,直接用 -animationForKey:來檢索圖層正在進行的動畫可以返回正確的動畫對象勇哗,但是修改它的屬性將會拋出異常。
如果移除圖層正在進行的動畫寸齐,圖層將會急速返回動畫之前的狀態(tài)欲诺。但如果在動畫移除之前拷貝呈現(xiàn)圖層到模型圖層,動畫將會看起來暫停在那里渺鹦。但是不好的地方在于之后就不能再恢復動畫了扰法。
一個簡單的方法是可以利用CAMediaTiming來暫停圖層本身。如果把圖層的speed設(shè)置成0毅厚,它會暫停任何添加到圖層上的動畫塞颁。類似的,設(shè)置speed大于1.0將會快進吸耿,設(shè)置成一個負值將會倒回動畫祠锣。
通過增加主窗口圖層的speed,可以暫停整個應(yīng)用程序的動畫咽安。這對UI自動化提供了好處锤岸,我們可以加速所有的視圖動畫來進行自動化測試(注意對于在主窗口之外的視圖并不會被影響,比如UIAlertview)板乙。可以在app delegate設(shè)置如下進行驗證:
self.window.layer.speed =100;
你也可以通過這種方式來減速拳氢,但其實也可以在模擬器通過切換慢速動畫來實現(xiàn)募逞。
手動動畫(圖層的timeOffset)
timeOffset一個很有用的功能在于你可以它可以讓你手動控制動畫進程,通過設(shè)置speed為0馋评,可以禁用動畫的自動播放放接,然后來使用timeOffset來來回顯示動畫序列。這可以使得運用手勢來手動控制動畫變得很簡單留特。
@property (nonatomic, strong) CALayer *doorLayer;@end@implementationViewController- (void)viewDidLoad
{
[super viewDidLoad];//add the doorself.doorLayer =[CALayer layer];
self.doorLayer.frame= CGRectMake(0,0,128,256);
self.doorLayer.position= CGPointMake(150-64,150);
self.doorLayer.anchorPoint= CGPointMake(0,0.5);
self.doorLayer.contents= (__bridgeid)[UIImage imageNamed:@"bjl_list_02"].CGImage;
[self.view.layer addSublayer:self.doorLayer];//apply perspective transformCATransform3D perspective =CATransform3DIdentity;
perspective.m34= -1.0/500.0;
self.view.layer.sublayerTransform=perspective;//add pan gesture recognizer to handle swipesUIPanGestureRecognizer *pan =[[UIPanGestureRecognizer alloc] init];
[pan addTarget:self action:@selector(pan:)];
[self.view addGestureRecognizer:pan];//pause all layer animationsself.doorLayer.speed =0.0;//apply swinging animation (which won't play because layer is paused)CABasicAnimation *animation =[CABasicAnimation animation];
animation.keyPath=@"transform.rotation.y";
animation.toValue= @(-M_PI_2);
animation.duration=1.0;
[self.doorLayer addAnimation:animation forKey:nil];
}
- (void)pan:(UIPanGestureRecognizer *)pan
{//get horizontal component of pan gestureCGFloat x =[pan translationInView:self.view].x;//convert from points to animation duration//using a reasonable scale factorx /=200.0f;//update timeOffset and clamp resultCFTimeInterval timeOffset =self.doorLayer.timeOffset;
timeOffset= MIN(0.999, MAX(0.0, timeOffset -x));
self.doorLayer.timeOffset=timeOffset;//reset pan gesture[pan setTranslation:CGPointZero inView:self.view];
}
CPU VS GPU
動畫和屏幕上組合的圖層實際上被一個單獨的進程管理纠脾,而不是你的應(yīng)用程序。這個進程就是所謂的渲染服務(wù)蜕青。在iOS5和之前的版本是SpringBoard進程(同時管理著iOS的主屏)苟蹈。在iOS6之后的版本中叫做BackBoard。
一件重要的事情就是性能測試一定要用發(fā)布配置右核,而不是調(diào)試模式慧脱。因為當用發(fā)布環(huán)境打包的時候,編譯器會引入一系列提高性能的優(yōu)化贺喝,例如去掉調(diào)試符號或者移 除并重新組織代碼菱鸥。你也可以自己做到這些宗兼,例如在發(fā)布環(huán)境禁用NSLog語句。你只關(guān)心發(fā)布性能氮采,那才是你需要測試的點殷绍。
Core Animation工具也提供了一系列復選框選項來幫助調(diào)試渲染瓶頸:
Color Blended Layers - 這個選項基于渲染程度對屏幕中的混合區(qū)域進行綠到紅的高亮(也就是多個半透明圖層的疊加)。由于重繪的原因鹊漠,混合對GPU性能會有影響主到,同時也是滑動或者動畫幀率下降的罪魁禍首之一。
ColorHitsGreenandMissesRed - 當使用shouldRasterizep屬性的時候贸呢,耗時的圖層繪制會被緩存镰烧,然后當做一個簡單的扁平圖片呈現(xiàn)。當緩存再生的時候這個選項就用紅色對柵格 化圖層進行了高亮楞陷。如果緩存頻繁再生的話怔鳖,就意味著柵格化可能會有負面的性能影響了(更多關(guān)于使用shouldRasterize的細節(jié)見第15章“圖層 性能”)。
Color Copied Images - 有時候寄宿圖片的生成意味著Core Animation被強制生成一些圖片固蛾,然后發(fā)送到渲染服務(wù)器结执,而不是簡單的指向原始指針。這個選項把這些圖片渲染成藍色艾凯。復制圖片對內(nèi)存和CPU使用來 說都是一項非常昂貴的操作献幔,所以應(yīng)該盡可能的避免。
Color Immediately - 通常Core Animation Instruments以每毫秒10次的頻率更新圖層調(diào)試顏色趾诗。對某些效果來說蜡感,這顯然太慢了。這個選項就可以用來設(shè)置每幀都更新(可能會影響到渲染性 能恃泪,而且會導致幀率測量不準郑兴,所以不要一直都設(shè)置它)。
Color Misaligned Images - 這里會高亮那些被縮放或者拉伸以及沒有正確對齊到像素邊界的圖片(也就是非整型坐標)贝乎。這些中的大多數(shù)通常都會導致圖片的不正城榱縮放,如果把一張大圖當縮 略圖顯示览效,或者不正確地模糊圖像却舀,那么這個選項將會幫你識別出問題所在。
Color Offscreen-Rendered Yellow - 這里會把那些需要離屏渲染的圖層高亮成黃色锤灿。這些圖層很可能需要用shadowPath或者shouldRasterize來優(yōu)化挽拔。
Color OpenGL Fast Path Blue - 這個選項會對任何直接使用OpenGL繪制的圖層進行高亮。如果僅僅使用UIKit或者Core Animation的API衡招,那么不會有任何效果篱昔。如果使用GLKView或者CAEAGLLayer,那如果不顯示藍色塊的話就意味著你正在強制CPU 渲染額外的紋理,而不是繪制到屏幕州刽。
Flash Updated Regions - 這個選項會對重繪的內(nèi)容高亮成黃色(也就是任何在軟件層面使用Core Graphics繪制的圖層)空执。這種繪圖的速度很慢。如果頻繁發(fā)生這種情況的話穗椅,這意味著有一個隱藏的bug或者說通過增加緩存或者使用替代方案會有提升 性能的空間辨绊。