iOS動(dòng)畫篇之CoreAnimation動(dòng)畫
9月 22, 2016發(fā)布在Objective-C
App如果想被大眾喜歡,漂亮的UI和精美的動(dòng)畫都是必不可少的,蘋果雖然為UIView提供了一些常用動(dòng)畫,但是大部分看起來比較不錯(cuò)的效果都是通過操作Layer層實(shí)現(xiàn)的,因此了解核心動(dòng)畫是必要的.CoreAnimation是直接作用在CALayer上的(并非UIView上)非常強(qiáng)大的跨Mac OS X和iOS平臺(tái)的動(dòng)畫處理API,Core Animation的動(dòng)畫執(zhí)行過程都是在后臺(tái)操作的,不會(huì)阻塞主線程。
開發(fā)中用的最多的是CoreAnimation動(dòng)畫庫,簡(jiǎn)稱是CA,所以動(dòng)畫類都是CA開頭。所有的動(dòng)畫類都在QuartzCore庫中,在iOS7之前使用需要#import ,iOS7之后系統(tǒng)已經(jīng)將其自動(dòng)導(dǎo)入了。CoreAnimation動(dòng)畫都是作用在layer上。
先來看下動(dòng)畫類的層級(jí)關(guān)系:
關(guān)于上圖中的層級(jí)結(jié)構(gòu)只需要了解一下,用的多了,自然就記住了。本篇只講述CABasicAnimation、CAKeyframeAnimation、CAAnimationGroup的使用。
上面講了CA動(dòng)畫都是作用在Layer上,而CA動(dòng)畫中修改的也是Layer的動(dòng)畫屬性,可以產(chǎn)生動(dòng)畫的layer屬性也有Animatable標(biāo)識(shí)。
CABasicAnimation動(dòng)畫主要是設(shè)置某個(gè)動(dòng)畫屬性的初始值fromValue和結(jié)束值toValue,來產(chǎn)生動(dòng)畫效果。
先上個(gè)示例代碼,將一個(gè)視圖往上移動(dòng)一段距離:
CABasicAnimation*postionAnimation = [CABasicAnimationanimationWithKeyPath:@"position.y"];
postionAnimation.duration =1.0f;
postionAnimation.fromValue = @(self.squareView.center.y);
postionAnimation.toValue = @(self.squareView.center.y -300);
postionAnimation.removedOnCompletion =NO;
postionAnimation.delegate =self;
postionAnimation.autoreverses =YES;
postionAnimation.fillMode = kCAFillModeForwards;
postionAnimation.timingFunction = [CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.squareView.layer addAnimation:postionAnimation forKey:@"posstionAnimation"];
動(dòng)畫的創(chuàng)建使用animationWithKeyPath:,因?yàn)槭褂玫膋eyPath所以動(dòng)畫屬性或者其結(jié)構(gòu)體中元素都可以產(chǎn)生動(dòng)畫。
duration動(dòng)畫的時(shí)長。
fromValue和toValue是CABasicAnimation的屬性,都是id類型的,所以要將基本類型包裝成對(duì)象。
removedOnCompletion決定動(dòng)畫執(zhí)行完之后是否將該動(dòng)畫的影響移除,默認(rèn)是YES,則layer回到動(dòng)畫前的狀態(tài)。
fillMode是個(gè)枚舉值(四種),當(dāng)removedOnCompletion設(shè)置為NO之后才會(huì)起作用??梢栽O(shè)置layer是保持動(dòng)畫開始前的狀態(tài)還是動(dòng)畫結(jié)束后的狀態(tài),或是其他的。
autoreverses表示動(dòng)畫結(jié)束后是否 backwards(回退) 到動(dòng)畫開始前的狀態(tài)??膳c上面兩個(gè)屬性組合出不同效果。
timingFunction動(dòng)畫的運(yùn)動(dòng)是勻速線性的還是先快后慢等,類似UIView動(dòng)畫的opitions。另外,CAMediaTimingFunction 方法可以自定義。
delegate代理,兩個(gè)動(dòng)畫代理方法:- (void)animationDidStart:(CAAnimation *)anim; 和- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
-(void)addAnimation:(CAAnimation *)anim forKey:(nullable NSString *)key; 給某個(gè)layer添加動(dòng)畫,與之對(duì)應(yīng)的移除某個(gè)動(dòng)畫是- (void)removeAnimationForKey:(NSString *)key;
還有一些其他的屬性,就不一一介紹了,可以在使用的使用去.h文件中查看。
在這里簡(jiǎn)單介紹一下fillMode
注意:fillMode這個(gè)屬性,必須要配合下面這個(gè)屬性來使用。這個(gè)屬性的默認(rèn)值是YES(回到原處),此時(shí)fillMode是沒有作用的如果設(shè)置為NO那么就需要設(shè)置一個(gè)fillMode屬性,就是動(dòng)畫結(jié)束之后的狀態(tài),如果不設(shè)置,動(dòng)畫也會(huì)回到原處。
postionAnimation.removedOnCompletion = NO;
kCAFillModeRemoved 這個(gè)是默認(rèn)值,也就是說當(dāng)動(dòng)畫開始前和動(dòng)畫結(jié)束后,動(dòng)畫對(duì)layer都沒有影響,動(dòng)畫結(jié)束后,layer會(huì)恢復(fù)到之前的狀態(tài)
kCAFillModeForwards 當(dāng)動(dòng)畫結(jié)束后,layer會(huì)一直保持著動(dòng)畫最后的狀態(tài)
kCAFillModeBackwards 這個(gè)和kCAFillModeForwards是相對(duì)的,就是在動(dòng)畫開始前,你只要將動(dòng)畫加入了
一個(gè)layer,layer便立即進(jìn)入動(dòng)畫的初始狀態(tài)并等待動(dòng)畫開始.你可以這樣設(shè)定測(cè)試代碼,將一個(gè)動(dòng)畫加入一個(gè)
layer的時(shí)候延遲5秒執(zhí)行.然后就會(huì)發(fā)現(xiàn)在動(dòng)畫沒有開始的時(shí)候,只要?jiǎng)赢嫳患尤肓薼ayer,layer便處于動(dòng)畫初
始狀態(tài)
kCAFillModeBoth 理解了上面兩個(gè),這個(gè)就很好理解了,這個(gè)其實(shí)就是上面兩個(gè)的合成.動(dòng)畫加入后開始之
前,layer便處于動(dòng)畫初始狀態(tài),動(dòng)畫結(jié)束后layer保持動(dòng)畫最后的狀態(tài).
Z軸
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rotationAnimation.fromValue = [NSNumber numberWithFloat:0.0];
rotationAnimation.toValue = [NSNumber numberWithFloat:2*M_PI];
rotationAnimation.repeatCount = MAXFLOAT;
rotationAnimation.duration =10;
[self.rotationImgView.layer addAnimation:rotationAnimation forKey:@"transform.rotation.z"];
X軸
CABasicAnimation *rotationXAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
rotationXAnimation.fromValue = [NSNumber numberWithFloat:0.0];
rotationXAnimation.toValue = [NSNumber numberWithFloat:2*M_PI];
rotationXAnimation.repeatCount = MAXFLOAT;
rotationXAnimation.duration =3;
[self.rotationXImgView.layer addAnimation:rotationXAnimation forKey:@"transform.rotation.x"];
Y軸
CABasicAnimation *rotationYAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
rotationYAnimation.fromValue = [NSNumber numberWithFloat:0.0];
rotationYAnimation.toValue = [NSNumber numberWithFloat:2*M_PI];
rotationYAnimation.repeatCount = MAXFLOAT;
rotationYAnimation.duration =10;
[self.rotationYImgView.layer addAnimation:rotationYAnimation forKey:@"transform.rotation.y"];
任意方向放大
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.5];
scaleAnimation.autoreverses = YES;//自動(dòng)反向執(zhí)行動(dòng)畫效果
scaleAnimation.repeatCount = MAXFLOAT;
scaleAnimation.duration = 0.8;
[self.scaleImgView.layer addAnimation:scaleAnimation forKey:@"FlyElephant.scale"];
X軸放大
CABasicAnimation *scaleXAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.x"];
scaleXAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleXAnimation.toValue = [NSNumber numberWithFloat:1.5];
scaleXAnimation.autoreverses = YES;//自動(dòng)反向執(zhí)行動(dòng)畫效果
scaleXAnimation.repeatCount = MAXFLOAT;
scaleXAnimation.duration = 0.8;
[self.scaleXImgView.layer addAnimation:scaleXAnimation forKey:@"FlyElephant.scale.x"];
Y軸放大
CABasicAnimation *scaleYAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"];
scaleYAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleYAnimation.toValue = [NSNumber numberWithFloat:1.5];
scaleYAnimation.autoreverses = YES;//自動(dòng)反向執(zhí)行動(dòng)畫效果
scaleYAnimation.repeatCount = MAXFLOAT;
scaleYAnimation.duration = 0.8;
[self.scaleYImgView.layer addAnimation:scaleYAnimation forKey:@"FlyElephant.scale.y"];
Z軸放大
CABasicAnimation *scaleZAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.z"];
scaleZAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleZAnimation.toValue = [NSNumber numberWithFloat:1.5];
scaleZAnimation.autoreverses = YES;//自動(dòng)反向執(zhí)行動(dòng)畫效果
scaleZAnimation.repeatCount = MAXFLOAT;
scaleZAnimation.duration = 0.8;
[self.scaleZImgView.layer addAnimation:scaleZAnimation forKey:@"FlyElephant.scale.z"];
X軸平移
CABasicAnimation *translationX=[CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
translationX.toValue=@(200);
translationX.duration=5;
translationX.removedOnCompletion=NO;
translationX.fillMode=kCAFillModeForwards;
translationX.repeatCount=MAXFLOAT;
translationX.autoreverses=YES;
[self.translationXImgView.layer addAnimation:translationX forKey:@"FlyElephant.translation.x"];
Y軸平移
CABasicAnimation *translationY=[CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
translationY.toValue=@(100);
translationY.duration=5;
translationY.removedOnCompletion=NO;
translationY.fillMode=kCAFillModeForwards;
translationY.repeatCount=MAXFLOAT;
translationY.autoreverses=YES;
[self.translationYImgView.layer addAnimation:translationY forKey:@"FlyElephant.translation.y"];
XY軸平移
CABasicAnimation *translation=[CABasicAnimation animationWithKeyPath:@"transform.translation"];
translation.toValue=[NSValue valueWithCGPoint:CGPointMake(100, 100)];
translation.duration=5;
translation.removedOnCompletion=NO;
translation.fillMode=kCAFillModeForwards;
translation.repeatCount=MAXFLOAT;
translation.autoreverses=YES;
[self.translationImgView.layer addAnimation:translation forKey:@"FlyElephant.translation"];
動(dòng)畫實(shí)例圖:
CAKeyframeAnimation我們一般稱為關(guān)鍵幀動(dòng)畫,主要是利用其values屬性,設(shè)置多個(gè)關(guān)鍵幀屬性值,來產(chǎn)生動(dòng)畫。
CAKeyframeAnimation *keyAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
keyAnimation.duration = 1.0f;
keyAnimation.beginTime = CACurrentMediaTime() + 1.0;
CATransform3D transform1 = CATransform3DMakeScale(1.5, 1.5, 0);
CATransform3D transform2 = CATransform3DMakeScale(0.8, 0.8, 0);
CATransform3D transform3 = CATransform3DMakeScale(3, 3, 0);
keyAnimation.values = @[[NSValue valueWithCATransform3D:transform1],[NSValue valueWithCATransform3D:transform2],[NSValue valueWithCATransform3D:transform3]];
keyAnimation.keyTimes = @[@0,@0.5,@1];
keyAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
keyAnimation.removedOnCompletion = NO;
keyAnimation.fillMode = kCAFillModeForwards;
[_someView.layer addAnimation:keyAnimation forKey:nil];
beginTime也是CAAnimation類的屬性,可以設(shè)置動(dòng)畫延遲多久執(zhí)行,示例代碼是延遲1秒執(zhí)行。
values是CAKeyframeAnimation的屬性,設(shè)置keyPath屬性在幾個(gè)關(guān)鍵幀的值,也是id類型的。
keyTimes也是CAKeyframeAnimation的屬性,每個(gè)值對(duì)應(yīng)相應(yīng)關(guān)鍵幀的時(shí)間比例值。
timingFunctions也是CAKeyframeAnimation的屬性,對(duì)應(yīng)每個(gè)動(dòng)畫段的動(dòng)畫過渡情況;而timingFunction是CAAnimation的屬性。
CGPoint p1=CGPointMake(self.positionImgView.center.x, self.positionImgView.center.y);
CGPoint p2=CGPointMake(80, 100);
CGPoint p3=CGPointMake(100, 120);
CGPoint p4=CGPointMake(120, 150);
CGPoint p5=CGPointMake(140, 160);
NSArray *values=[NSArray arrayWithObjects:[NSValue valueWithCGPoint:p1],[NSValue valueWithCGPoint:p2],[NSValue valueWithCGPoint:p3],[NSValue valueWithCGPoint:p4],[NSValue valueWithCGPoint:p5], nil];
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
[animation setValues:values];
[animation setDuration:10.0];
[animation setCalculationMode:kCAAnimationCubic];
animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[self.positionImgView.layer addAnimation:animation forKey:@"FlyElephant.point"];
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path,NULL,self.positionImgView.center.x,self.positionImgView.center.y);
for(NSInteger i = 1; i < 5 i++){
CGPathAddLineToPoint(path, NULL, self.positionImgView.center.x+i*10,? ? self.positionImgView.center.y);
}
//曲線
CGPathAddCurveToPoint(path,NULL,50.0,275.0,150.0,275.0,70.0,120.0);
CGPathAddCurveToPoint(path,NULL,150.0,275.0,250.0,275.0,90.0,120.0);
CGPathAddCurveToPoint(path,NULL,250.0,275.0,350.0,275.0,110.0,120.0);
CGPathAddCurveToPoint(path,NULL,350.0,275.0,450.0,275.0,130.0,120.0);
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
[animation setPath:path];
[animation setDuration:3.0];
// [animation setAutoreverses:YES];
CFRelease(path);
[self.positionImgView.layer addAnimation:animation:@"FlyElephant"];
通過代碼我們發(fā)現(xiàn),Path和values接收都是一個(gè)數(shù)組,而不是一個(gè)固定值,這里面我們沒有設(shè)置keyTimes,下面看一個(gè)常見的抖動(dòng)效果:
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.keyPath = @"position.x";
animation.values = @[ @0, @20, @-20, @20, @0 ];
animation.keyTimes = @[ @0, @(1 /8.0), @(1/ 2.0), @(7/ 8.0), @1 ];
animation.duration =0.5;
animation.additive = YES;
[self.textField.layer addAnimation:animation forKey:@"FlyElephant.Shake"];
CAAnimationGroup的用法與其他動(dòng)畫類一樣,都是添加到layer上,比CAAnimation多了一個(gè)animations屬性。
先看示例代碼,動(dòng)畫效果是視圖一邊向上移動(dòng),一邊繞Y軸旋轉(zhuǎn):
CABasicAnimation *rotationYAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
rotationYAnimation.fromValue = @0;
rotationYAnimation.toValue = @(M_PI);
rotationYAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
CABasicAnimation *postionAnimation = [CABasicAnimation animationWithKeyPath:@"position.y"];
postionAnimation.fromValue = @(_markView.center.y);
postionAnimation.toValue = @(_markView.center.y - 100);
postionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.duration = kUpDuration;
animationGroup.removedOnCompletion = NO;
animationGroup.fillMode = kCAFillModeForwards;
animationGroup.delegate = self;
animationGroup.animations = @[rotationYAnimation, postionAnimation];
[_markView.layer addAnimation:animationGroup forKey:kJumpAnimation];
CAAnimationGroup的animations中可以放其他任何動(dòng)畫類(包括CAAnimationGroup),需要注意的是animations里的動(dòng)畫設(shè)置了duration之后動(dòng)畫可能會(huì)有不同,一般里面不設(shè)置,在最外層設(shè)置group的duration即可。
最開始做動(dòng)畫一般都會(huì)對(duì)keyPath這個(gè)值莫名其妙,因?yàn)樗皇浅A?,需要變換的時(shí)候找不到對(duì)應(yīng)的需要設(shè)置的值,如果你在網(wǎng)上搜索,很可能看到的是這張圖:
下面這張圖你基本上是找不到的,如下:
CATransition一般來做轉(zhuǎn)場(chǎng)動(dòng)畫。先上gif動(dòng)畫效果
//修改視圖的背景色
_someView.backgroundColor = [UIColor greenColor];
CATransition *animation = [CATransition animation];
animation.duration = 0.5;
/* 這里可設(shè)置的參數(shù)有:kCATransitionFade、kCATransitionPush、kCATransitionReveal、kCATransitionMoveIn、
"cube"、"suckEffect"、"oglFlip"、"rippleEffect"、"pageCurl"、"pageUnCurl"、"cameraIrisHollowOpen"、
"cameraIrisHollowClose",這些都是動(dòng)畫類型
*/
animation.type = @"cube";
// 動(dòng)畫執(zhí)行的方向,kCATransitionFromRight、kCATransitionFromLeft、kCATransitionFromTop、kCATransitionFromBottom
animation.subtype = kCATransitionFromRight;
animation.timingFunction = UIViewAnimationOptionCurveEaseInOut;
[_someView.layer addAnimation:animation forKey:nil];
//也可以寫這里
//? ? _someView.backgroundColor = [UIColor greenColor];
只需要在動(dòng)畫開始前或者動(dòng)畫開始后替換掉視圖上顯示的內(nèi)容即可。具體可以看我的這篇博客iOS動(dòng)畫之CATransition動(dòng)畫
附加的內(nèi)容是關(guān)于CALayer和UIBezierPath。個(gè)人覺得理解了UIBezierPath和CALayer,才能更好的理解CoreAnimation動(dòng)畫。
UIBezierPath主要是用來繪制路徑的,分為一階、二階…..n階。一階是直線,二階以上才是曲線。而最終路徑的顯示還是得依靠CALayer。用CoreGraphics將路徑繪制出來,最終也是繪制到CALayer上。
方法一:構(gòu)造bezierPath對(duì)象,一般用于自定義路徑。
方法二:繪制圓弧路徑,參數(shù)1是中心點(diǎn)位置,參數(shù)2是半徑,參數(shù)3是開始的弧度值,參數(shù)4是結(jié)束的弧度值,參數(shù)5是是否順時(shí)針(YES是順時(shí)針方向,NO逆時(shí)針)。
方法三:根據(jù)某個(gè)路徑繪制路徑。
方法四:根據(jù)某個(gè)CGRect繪制內(nèi)切圓或橢圓(CGRect是正方形即為圓,為長方形則為橢圓)。
方法五:根據(jù)某個(gè)CGRect繪制路徑。
方法六:繪制帶圓角的矩形路徑,參數(shù)2哪個(gè)角,參數(shù)3,橫、縱向半徑。
方法七:繪制每個(gè)角都是圓角的矩形,參數(shù)2是半徑。
自定義路徑時(shí)常用的API:
- (void)moveToPoint:(CGPoint)point; // 移到某個(gè)點(diǎn)
- (void)addLineToPoint:(CGPoint)point; // 繪制直線
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2; //繪制貝塞爾曲線
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint; // 繪制規(guī)則的貝塞爾曲線
- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise
// 繪制圓形曲線
- (void)appendPath:(UIBezierPath *)bezierPath; // 拼接曲線
有三種方式:1、直接使用UIBezierPath的方法;2、使用CoreGraphics繪制;3、利用CAShapeLayer繪制。
示例代碼如下,繪制一個(gè)右側(cè)為弧型的視圖:
- (void)drawRect:(CGRect)rect
{
UIColor *fillColor = [UIColor colorWithRed:0.0 green:0.722 blue:1.0 alpha:1.0];
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(0, 0)];
[bezierPath addLineToPoint:CGPointMake(rect.size.width - spaceWidth, 0)];
[bezierPath addQuadCurveToPoint:CGPointMake(rect.size.width - spaceWidth, rect.size.height) controlPoint:CGPointMake(rect.size.width - spaceWidth + _deltaWith, rect.size.height * 0.5)];
[bezierPath addLineToPoint:CGPointMake(0, rect.size.height)];
[bezierPath addLineToPoint:CGPointMake(0, 0)];
[bezierPath closePath];
// 1、bezierPath方法
//? ? [fillColor setFill];
//? ? [bezierPath fill];
// 2、使用CoreGraphics
//? ? CGContextRef ctx = UIGraphicsGetCurrentContext();
//? ? CGContextAddPath(ctx, bezierPath.CGPath);
//? ? CGContextSetFillColorWithColor(ctx, fillColor.CGColor);
//? ? CGContextFillPath(ctx);
// 3.CAShaperLayer
[self.layer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = bezierPath.CGPath;
shapeLayer.fillColor = fillColor.CGColor;
[self.layer addSublayer:shapeLayer];
}
上圖這樣的視圖是用UIBezierPath用多個(gè)CAShapeLayer制作出來的,而動(dòng)畫效果只需要改變進(jìn)度的layer的strokeEnd和修改下面代表水面進(jìn)度的視圖位置即可。動(dòng)畫的組合也可以有多種方式組合
動(dòng)畫的示例代碼:
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated duration:(NSTimeInterval)duration
{
CGFloat tempPro = progress;
if (tempPro > 1.0) {
tempPro = 1.0;
} else if (progress < 0.0){
tempPro = 0.0;
}
_progress = tempPro;
CABasicAnimation *pathAniamtion = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAniamtion.duration = duration;
pathAniamtion.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pathAniamtion.fromValue = [NSNumber numberWithFloat:0.0f];
pathAniamtion.toValue = [NSNumber numberWithFloat:_progress];
pathAniamtion.autoreverses = NO;
[_progressLayer addAnimation:pathAniamtion forKey:nil];
// 水位上升的動(dòng)畫
if (!_showSolidAnimation) {
return;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
_imageView.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:duration animations:^{
CGRect rect = _imageView.frame;
CGFloat dy = rect.size.height * progress;
_imageView.transform = CGAffineTransformMakeTranslation(0, -dy);
}];
});
}
在用自定義的CAShapeLayer做動(dòng)畫時(shí),建議在動(dòng)畫開始前先將動(dòng)畫屬性與最終的屬性值一致,再開始動(dòng)畫,不要使用removedOnCompletion控制最終的狀態(tài),這在WWDC蘋果這么建議