接上一篇博客 iOS 動畫篇(一) Core Animation
CAShapeLayer是CALayer的一個子類,使用這個類能夠很輕易實現曲線的動畫。
先來一個折線動畫效果:
示例代碼:
//1.生成path UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(0, 0)]; [path addLineToPoint:CGPointMake(50, 50)]; [path addLineToPoint:CGPointMake(70, 150)]; [path addLineToPoint:CGPointMake(100, 100)]; [path addLineToPoint:CGPointMake(150, 130)]; [path addLineToPoint:CGPointMake(170, 200)]; self.shapeLayer.path = path.CGPath; //設置animation CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; strokeAnimation.fromValue = @0; strokeAnimation.toValue = @1; strokeAnimation.duration = 5.f; CABasicAnimation *lineWidthAnimation = [CABasicAnimation animationWithKeyPath:@"lineWidth"]; lineWidthAnimation.fromValue = @1; lineWidthAnimation.toValue = @5; lineWidthAnimation.duration = 5.f; CABasicAnimation *strokeColorAnimation = [CABasicAnimation animationWithKeyPath:@"strokeColor"]; strokeColorAnimation.fromValue = (id)([UIColor redColor].CGColor); strokeColorAnimation.toValue = (id)([UIColor magentaColor].CGColor); strokeColorAnimation.duration = 5.f; CAAnimationGroup *group = [CAAnimationGroup animation]; group.animations = @[strokeAnimation, lineWidthAnimation, strokeColorAnimation]; group.duration = 5.f; group.fillMode = kCAFillModeForwards; group.removedOnCompletion = NO; [self.shapeLayer addAnimation:group forKey:@"groupAnimation"];
現在介紹CAShapeLayer,CAShapeLayer幾乎所有的屬性都可以用來做動畫,比如說path、strokeEnd、strokeStart、lineWidth等等,利用這些屬性可以實現多種曲線動畫。
接下來,介紹一個CAShapeLayer與貝塞爾曲線結合的曲線動畫,效果圖:
代碼:
//二次貝塞爾曲線 UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(0, self.shapeLayer.bounds.size.height / 2)]; [path addCurveToPoint:CGPointMake(self.shapeLayer.bounds.size.width, 100) controlPoint1:CGPointMake(50, 0) controlPoint2:CGPointMake(150, 200)]; self.shapeLayer.path = path.CGPath; //繪制動畫 CABasicAnimation *strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; strokeEndAnimation.fromValue = @0.5; strokeEndAnimation.toValue = @1; strokeEndAnimation.duration = 5.f; [self.shapeLayer addAnimation:strokeEndAnimation forKey:@"strokeAnimation"]; CABasicAnimation *strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; strokeStartAnimation.fromValue = @0.5; strokeStartAnimation.toValue = @0; strokeStartAnimation.duration = 5.f; [self.shapeLayer addAnimation:strokeStartAnimation forKey:@"strokeStartAnimation"];
再來一個看着酷一點的loading動畫,效果:
代碼如下:
self.shapeLayer.backgroundColor = [UIColor clearColor].CGColor; self.shapeLayer.strokeColor = [UIColor redColor].CGColor; self.shapeLayer.fillColor = [UIColor clearColor].CGColor; self.shapeLayer.lineWidth = 5.f; UIBezierPath *storkePath = [UIBezierPath bezierPathWithOvalInRect:self.shapeLayer.bounds]; self.shapeLayer.path = storkePath.CGPath; self.shapeLayer.strokeStart = 0; self.shapeLayer.strokeEnd = 0.1; //旋轉動畫 CABasicAnimation *rotateAnimaiton = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; rotateAnimaiton.duration = 1.f; rotateAnimaiton.repeatCount = CGFLOAT_MAX; rotateAnimaiton.removedOnCompletion = NO; rotateAnimaiton.fillMode = kCAFillModeForwards; rotateAnimaiton.toValue = @(M_PI * 2); //stroke動畫 CABasicAnimation *storkeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; storkeAnimation.duration = 2.f; storkeAnimation.repeatCount = CGFLOAT_MAX; storkeAnimation.fillMode = kCAFillModeForwards; storkeAnimation.removedOnCompletion = NO; storkeAnimation.toValue = @(1); CAAnimationGroup *animationGroup = [CAAnimationGroup animation]; animationGroup.duration = 2.f; animationGroup.repeatCount =CGFLOAT_MAX; animationGroup.fillMode = kCAFillModeForwards; animationGroup.removedOnCompletion = NO; animationGroup.animations = @[rotateAnimaiton, storkeAnimation]; animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; [self.shapeLayer addAnimation:animationGroup forKey:@"indicatorAnimation"];
現在我們來看一個CAShapeLayer與mask結合的動畫
代碼:
CAShapeLayer *shapeLayer = [CAShapeLayer layer]; self.shapeLayer.mask = shapeLayer; UIBezierPath *fromPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 200, 0)]; UIBezierPath *toPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 200, 200)]; shapeLayer.path = fromPath.CGPath; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"]; animation.fromValue = (id)fromPath.CGPath; animation.toValue = (id)toPath.CGPath; animation.duration = 5.f; animation.removedOnCompletion = NO; animation.fillMode = kCAFillModeForwards; [shapeLayer addAnimation:animation forKey:@"animation"];
最后再介紹一個登錄動畫:
分析:這個登錄動畫一共分為三步
1. 在button上添加一個shapeLayer,用path屬性實現layer的展開動畫
2. 在展開動畫結束后,為button設置一個shapeLayer的mask,利用layer的path和opacity屬性實現收起按鈕動畫
3. 添加一個loading動畫到view上
詳情見代碼:
- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"一個復雜一點的登錄動畫"); [self.shapeLayer removeFromSuperlayer]; UIButton *startButton = ({ UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem]; btn.backgroundColor = [UIColor purpleColor]; [btn setTitle:@"start" forState:UIControlStateNormal]; btn.frame = (CGRect){{0, 0}, {200, 50}}; btn.center = self.view.center; [btn addTarget:self action:@selector(startAction:) forControlEvents:UIControlEventTouchUpInside]; btn; }); [self.view addSubview:startButton]; self.startButton = startButton; } - (IBAction)startAction:(UIButton *)sender { [self addMaskAnimation]; } - (void)addMaskAnimation { CAShapeLayer *shapeLayer = [CAShapeLayer new]; shapeLayer.frame = self.startButton.bounds; shapeLayer.fillColor = [UIColor whiteColor].CGColor; shapeLayer.strokeColor = [UIColor whiteColor].CGColor; shapeLayer.opacity = .3f; shapeLayer.path = [UIBezierPath bezierPathWithRect:CGRectMake(self.startButton.bounds.size.width / 2, 0, 1, self.startButton.bounds.size.height)].CGPath;//不初始化則無動畫效果 [self.startButton.layer addSublayer:shapeLayer]; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"]; animation.duration = 0.5f; animation.toValue = (__bridge id)[UIBezierPath bezierPathWithRect:self.startButton.bounds].CGPath; animation.fillMode = kCAFillModeForwards; animation.removedOnCompletion = NO; [shapeLayer addAnimation:animation forKey:@"shapeAnimation"]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self addPackupAnimation]; }); } - (void)addPackupAnimation { CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.frame = self.startButton.bounds; self.startButton.layer.mask = maskLayer; //path動畫 CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; pathAnimation.duration = 0.3f; pathAnimation.removedOnCompletion = NO; pathAnimation.toValue = (__bridge id)[UIBezierPath bezierPathWithArcCenter:CGPointMake(self.startButton.bounds.size.width / 2, self.startButton.bounds.size.height / 2) radius:1 startAngle:0 endAngle:M_PI * 2 clockwise:YES].CGPath; pathAnimation.fromValue = (__bridge id)[UIBezierPath bezierPathWithArcCenter:CGPointMake(self.startButton.bounds.size.width / 2, self.startButton.bounds.size.height / 2) radius:self.startButton.bounds.size.width / 2 startAngle:0 endAngle:M_PI * 2 clockwise:YES].CGPath; pathAnimation.fillMode = kCAFillModeForwards; //透明度動畫 CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; opacityAnimation.duration = 0.3f; opacityAnimation.toValue = @(1); opacityAnimation.fromValue = @(0); opacityAnimation.removedOnCompletion = YES; opacityAnimation.fillMode = kCAFillModeForwards; CAAnimationGroup *group = [CAAnimationGroup new]; group.animations = @[pathAnimation]; group.removedOnCompletion = NO; group.fillMode = kCAFillModeForwards; group.duration = pathAnimation.duration; [maskLayer addAnimation:group forKey:@"packupAnimation"]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.startButton.hidden = YES; [self addLoadingAnimation]; }); } - (void)addLoadingAnimation { CAShapeLayer *shapeLayer = ({ CAShapeLayer *layer = [CAShapeLayer layer]; layer.position = self.view.center; layer.bounds = CGRectMake(0, 0, 50, 50); layer.backgroundColor = [UIColor clearColor].CGColor; layer.strokeColor = [UIColor redColor].CGColor; layer.fillColor = [UIColor clearColor].CGColor; layer.lineWidth = 5.f; UIBezierPath *storkePath = [UIBezierPath bezierPathWithOvalInRect:layer.bounds]; layer.path = storkePath.CGPath; layer.strokeStart = 0; layer.strokeEnd = 0.1; layer; }); [self.view.layer addSublayer:shapeLayer]; //旋轉動畫 CABasicAnimation *rotateAnimaiton = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; rotateAnimaiton.duration = 1.f; rotateAnimaiton.repeatCount = CGFLOAT_MAX; rotateAnimaiton.removedOnCompletion = NO; rotateAnimaiton.fillMode = kCAFillModeForwards; rotateAnimaiton.toValue = @(M_PI * 2); //stroke動畫 CABasicAnimation *storkeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; storkeAnimation.duration = 2.f; storkeAnimation.repeatCount = CGFLOAT_MAX; storkeAnimation.fillMode = kCAFillModeForwards; storkeAnimation.removedOnCompletion = NO; storkeAnimation.toValue = @(1); CAAnimationGroup *animationGroup = [CAAnimationGroup animation]; animationGroup.duration = 2.f; animationGroup.repeatCount =CGFLOAT_MAX; animationGroup.fillMode = kCAFillModeForwards; animationGroup.removedOnCompletion = NO; animationGroup.animations = @[rotateAnimaiton, storkeAnimation]; animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; [shapeLayer addAnimation:animationGroup forKey:@"indicatorAnimation"]; }
核心動畫就介紹到這,你可以在這里查看demo。
個人原創,轉載請注明出處 http://www.cnblogs.com/pretty-guy/p/8268745.html
下一篇博客打算介紹利用CADisplayLink與CoreGraphics結合實現動畫