CATransaction事務(wù)
<br />
CALayer的"Animatable"屬性的設(shè)置都應(yīng)該屬于某一個(gè)CATransaction事務(wù)砂吞,CATransaction的作用是保證多個(gè)"Animatable"的變化同時(shí)進(jìn)行跨细。也就是說CALayer的屬性改變需要依賴CATransaction掷豺。
CATransaction也分為隱式和顯示。
隱式:在某次RunLoop中設(shè)置了一個(gè)"Animatable"屬性逞盆,如果當(dāng)前沒有設(shè)置事務(wù),則會(huì)自動(dòng)創(chuàng)建一個(gè)CATransaction令野,并在當(dāng)前線程的下一個(gè)RunLoop中commit這個(gè)CATransaction轻专。
顯示: 就是直接調(diào)用CATransaction的[CATransaction begin]
王财,[CATransaction commit]
等相關(guān)方法卵迂。比如我們不希望self.subLayer.position = CGPointMake(100,100)
產(chǎn)生動(dòng)畫,則可以在CATransaction中設(shè)置 setDisableActions: YES
另外事務(wù)可以嵌套绒净,當(dāng)事務(wù)嵌套時(shí)见咒,只有最外層的事務(wù)commit之后,整個(gè)動(dòng)畫才開始挂疆。
<br />
自定義CALayer
<br />
自定義Layer有兩種方法:
- 通過delegate改览,在delegate里面實(shí)現(xiàn)layer內(nèi)容的繪制及渲染
// 方法一
CALayer *customerLayer = [CALayer layer];
customerLayer.bounds = CGRectMake(0, 0, 200, 200);
customerLayer.position = CGPointMake(self.view.frame.size.width * 0.5, self.view.frame.size.height * 0.5);
customerLayer.backgroundColor = [UIColor redColor].CGColor;
customerLayer.delegate = self;
// - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx 該代理方法不會(huì)自動(dòng)調(diào)用 必須主動(dòng)調(diào)用setNeedDisplay方法才會(huì)觸發(fā)
[customerLayer setNeedsDisplay];
[self.view.layer addSublayer:customerLayer];
代理方法
#pragma mark - layer delegate
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));
CGContextSetRGBFillColor(ctx, 0, 1, 0, 1);
CGContextFillPath(ctx);
}
- 通過override自定義layer里面的
- (void)drawInContext:(CGContextRef)ctx
// 方法二
WYLayer *customerLayer = [WYLayer layer];
customerLayer.bounds = CGRectMake(0, 0, 200, 200);
customerLayer.position = CGPointMake(self.view.frame.size.width * 0.5, self.view.frame.size.height * 0.5);
// - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx 該代理方法不會(huì)自動(dòng)調(diào)用 必須主動(dòng)調(diào)用setNeedDisplay方法才會(huì)觸發(fā)
[customerLayer setNeedsDisplay];
[self.view.layer addSublayer:customerLayer];
自定義WYLayer
#import "WYLayer.h"
@implementation WYLayer
// 重寫該方法, 在該方法中給layer上繪制圖形
// 注意CALayer中的drawInContext方法, 不會(huì)自動(dòng)調(diào)用
// 只能自己通過setNeedDisplay方法調(diào)用
- (void)drawInContext:(CGContextRef)ctx {
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));
// Attention:不能用UIKit框架中的類
// [[UIColor redColor] set];
CGContextSetRGBFillColor(ctx, 0, 1, 0, 1);
CGContextFillPath(ctx);
}
@end
<br />
CABaseAnimation
CAPropertyAnimation的子類
屬性解析:
fromValue:keyPath
相應(yīng)屬性的初始值
toValue:keyPath
相應(yīng)屬性的結(jié)束值
隨著動(dòng)畫的進(jìn)行,在長(zhǎng)度為duration
的持續(xù)時(shí)間內(nèi)缤言,keyPath
相應(yīng)屬性的值從fromValue
漸漸地變?yōu)?code>toValue
Attention:如果fillMode=kCAFillModeForwards和removedOnComletion=NO
宝当,那么在動(dòng)畫執(zhí)行完畢后,圖層會(huì)保持顯示動(dòng)畫執(zhí)行后的狀態(tài)胆萧。但在實(shí)質(zhì)上庆揩,圖層的屬性值還是動(dòng)畫執(zhí)行前的初始值,并沒有真正被改變跌穗。比如订晌,CALayer的position
初始值為(0,0),CABasicAnimation的fromValue
為(10,10)蚌吸,toValue
為(100,100)锈拨,雖然動(dòng)畫執(zhí)行完畢后圖層保持在(100,100)這個(gè)位置,實(shí)質(zhì)上圖層的position
還是為(0,0)
// 創(chuàng)建基本動(dòng)畫
CABasicAnimation *animation = [CABasicAnimation animation];
// 設(shè)置動(dòng)畫類型
animation.keyPath = @"transform";
// 設(shè)置動(dòng)畫結(jié)束后不刪除動(dòng)畫
animation.removedOnCompletion = NO;
// 設(shè)置動(dòng)畫結(jié)束后的最新狀態(tài)
animation.fillMode = kCAFillModeForwards;
// 設(shè)置動(dòng)畫時(shí)長(zhǎng)
animation.duration = 4;
// 設(shè)置移動(dòng)位置
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2, 0, 0, 1)];
[self.myLayer addAnimation:animation forKey:nil];
<br />
CAKeyFrameAnimation
CApropertyAnimation的子類套利,跟CABasicAnimation的區(qū)別是:CABasicAnimation只能從一個(gè)數(shù)值fromValue
變到另一個(gè)數(shù)值toValue
推励,而CAKeyframeAnimation會(huì)使用一個(gè)NSArray保存這些數(shù)值。
屬性解析:
values:就是上述的NSArray對(duì)象肉迫。里面的元素稱為”關(guān)鍵幀”(keyframe)验辞。動(dòng)畫對(duì)象會(huì)在指定的時(shí)間duration
內(nèi),依次顯示values
數(shù)組中的每一個(gè)關(guān)鍵幀
path:可以設(shè)置一個(gè)CGPathRef\CGMutablePathRef
,讓層跟著路徑移動(dòng)喊衫。path
只對(duì)CALayer的anchorPoint
和position
起作用跌造。<u>如果你設(shè)置了path
,那么values
將被忽略</u>族购。
keyTimes:可以為對(duì)應(yīng)的關(guān)鍵幀指定對(duì)應(yīng)的時(shí)間點(diǎn),其取值范圍為0到1.0,keyTimes中的每一個(gè)時(shí)間值都對(duì)應(yīng)values中的每一幀.當(dāng)keyTimes沒有設(shè)置的時(shí)候,各個(gè)關(guān)鍵幀的時(shí)間是平分的壳贪。
CABasicAnimation可看做是最多只有2個(gè)關(guān)鍵幀的CAKeyframeAnimation。
關(guān)鍵幀動(dòng)畫的創(chuàng)建可以有兩種方式:
values
// 1.創(chuàng)建核心動(dòng)畫
CAKeyframeAnimation *keyAnima = [CAKeyframeAnimation animation];
// 1.1告訴系統(tǒng)執(zhí)行什么動(dòng)畫
keyAnima.keyPath = @"position";
// NSValue *v1 = [NSValue valueWithCGPoint:CGPointMake(0, 100)];
NSValue *v2 = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
NSValue *v3 = [NSValue valueWithCGPoint:CGPointMake(100, 200)];
NSValue *v4 = [NSValue valueWithCGPoint:CGPointMake(0, 200)];
NSValue *v5 = [NSValue valueWithCGPoint:CGPointMake(0, 100)];
keyAnima.values = @[v2, v3, v4, v5];
// keyAnima.keyTimes = @[@(0.5) ,@(0.5), @(0.5)];
keyAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
// 1.2保存執(zhí)行完之后的狀態(tài)
// 1.2.1執(zhí)行完之后不刪除動(dòng)畫
keyAnima.removedOnCompletion = NO;
// 1.2.2執(zhí)行完之后保存最新的狀態(tài)
keyAnima.fillMode = kCAFillModeForwards;
// 1.3設(shè)置動(dòng)畫時(shí)間
keyAnima.duration = 2;
// 2.觀察動(dòng)畫什么時(shí)候開始執(zhí)行, 以及什么時(shí)候執(zhí)行完畢
keyAnima.delegate = self;
// 2.添加核心動(dòng)畫
[self.customView.layer addAnimation:keyAnima forKey:nil];
path
// 1.創(chuàng)建核心動(dòng)畫
CAKeyframeAnimation *keyAnima = [CAKeyframeAnimation animation];
// 1.1告訴系統(tǒng)執(zhí)行什么動(dòng)畫
keyAnima.keyPath = @"position";
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, CGRectMake(0, 100, 200, 200));
keyAnima.path = path;
CGPathRelease(path);
// 1.2保存執(zhí)行完之后的狀態(tài)
// 1.2.1執(zhí)行完之后不刪除動(dòng)畫
keyAnima.removedOnCompletion = NO;
// 1.2.2執(zhí)行完之后保存最新的狀態(tài)
keyAnima.fillMode = kCAFillModeForwards;
// 1.3設(shè)置動(dòng)畫時(shí)間
keyAnima.duration = 2;
// 2.觀察動(dòng)畫什么時(shí)候開始執(zhí)行, 以及什么時(shí)候執(zhí)行完畢
keyAnima.delegate = self;
// 3.添加核心動(dòng)畫
[self.customView.layer addAnimation:keyAnima forKey:@"abc"];