接上一篇博客 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结合实现动画
转载于:https://www.cnblogs.com/pretty-guy/p/8268745.html