CALayer總結(jié)

轉(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è)置我們的字符串屬性,但是練習(xí)的目的是為了演示在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復(fù)制一個CAGradientLayer并將內(nèi)容繪制到一個普通圖層的寄宿圖也是有可能的,但是CAGradientLayer的真正好處在于繪制使用了硬件加速。

27.CAReplicatorLayer

CAReplicatorLayer的目的是為了高效生成許多相似的圖層。它會繪制一個或多個圖層的子圖層,并在每個復(fù)制體上應(yīng)用不同的變換。

instanceCount屬性指定了圖層需要重復(fù)多少次。instanceTransform指定了一個CATransform3D 3D變換(這種情況下,下一圖層的位移和旋轉(zhuǎn)將會移動到圓圈的下一個點)。變換是逐步增加的,每個實例都是相對于前一實例布局。這就是為什么這些復(fù)制體最終不會出現(xiàn)在同一位置上;

CAReplicatorLayer真正應(yīng)用到實際程序上的場景比如:一個游戲中導(dǎo)彈的軌跡云,或者粒子爆炸。除此之外,還有一個實際應(yīng)用是:反射。

28.CAScrollLayer

CAScrollLayer有一個-scrollToPoint:方法,它自動適應(yīng)bounds的原點以便圖層內(nèi)容出現(xiàn)在滑動的地方。注意,這就是它做的所有事情。前面提到過,Core Animation并不處理用戶輸入,所以CAScrollLayer并不負責(zé)將觸摸事件轉(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)圖層實際上是模型圖層的復(fù)制,但是它的屬性值代表了在任何指定時刻當前外觀效果。換句話說,你可以通過呈現(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ǔ)類,不能直接使用,負責(zé)動畫運行時間、速度的控制。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導(dǎo)致的延遲動畫不同,增加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)圖層到模型圖層,動畫將會看起來暫停在那里。但是不好的地方在于之后就不能再恢復(fù)動畫了。

一個簡單的方法是可以利用CAMediaTiming來暫停圖層本身。如果把圖層的speed設(shè)置成0,它會暫停任何添加到圖層上的動畫。類似的,設(shè)置speed大于1.0將會快進,設(shè)置成一個負值將會倒回動畫。

通過增加主窗口圖層的speed,可以暫停整個應(yīng)用程序的動畫。這對UI自動化提供了好處,我們可以加速所有的視圖動畫來進行自動化測試(注意對于在主窗口之外的視圖并不會被影響,比如UIAlertview)??梢栽赼pp 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工具也提供了一系列復(fù)選框選項來幫助調(diào)試渲染瓶頸:

Color Blended Layers - 這個選項基于渲染程度對屏幕中的混合區(qū)域進行綠到紅的高亮(也就是多個半透明圖層的疊加)。由于重繪的原因,混合對GPU性能會有影響,同時也是滑動或者動畫幀率下降的罪魁禍首之一。

ColorHitsGreenandMissesRed - 當使用shouldRasterizep屬性的時候,耗時的圖層繪制會被緩存,然后當做一個簡單的扁平圖片呈現(xiàn)。當緩存再生的時候這個選項就用紅色對柵格 化圖層進行了高亮。如果緩存頻繁再生的話,就意味著柵格化可能會有負面的性能影響了(更多關(guān)于使用shouldRasterize的細節(jié)見第15章“圖層 性能”)。

Color Copied Images - 有時候寄宿圖片的生成意味著Core Animation被強制生成一些圖片,然后發(fā)送到渲染服務(wù)器,而不是簡單的指向原始指針。這個選項把這些圖片渲染成藍色。復(fù)制圖片對內(nèi)存和CPU使用來 說都是一項非常昂貴的操作,所以應(yīng)該盡可能的避免。

Color Immediately - 通常Core Animation Instruments以每毫秒10次的頻率更新圖層調(diào)試顏色。對某些效果來說,這顯然太慢了。這個選項就可以用來設(shè)置每幀都更新(可能會影響到渲染性 能,而且會導(dǎo)致幀率測量不準,所以不要一直都設(shè)置它)。

Color Misaligned Images - 這里會高亮那些被縮放或者拉伸以及沒有正確對齊到像素邊界的圖片(也就是非整型坐標)。這些中的大多數(shù)通常都會導(dǎo)致圖片的不正??s放,如果把一張大圖當縮 略圖顯示,或者不正確地模糊圖像,那么這個選項將會幫你識別出問題所在。

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或者說通過增加緩存或者使用替代方案會有提升 性能的空間。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,686評論 6 30
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,258評論 5 13
  • Core Animation其實是一個令人誤解的命名。你可能認為它只是用來做動畫的,但實際上它是從一個叫做Laye...
    小貓仔閱讀 3,950評論 1 4
  • 前言 本文只要描述了iOS中的Core Animation(核心動畫:隱式動畫、顯示動畫)、貝塞爾曲線、UIVie...
    GitHubPorter閱讀 3,735評論 7 11
  • 書寫的很好,翻譯的也棒!感謝譯者,感謝感謝! iOS-Core-Animation-Advanced-Techni...
    錢噓噓閱讀 2,427評論 0 6

友情鏈接更多精彩內(nèi)容