您的位置:首页 > 移动开发 > IOS开发

iOS 动画篇 (二) CAShapeLayer与CoreAnimation结合使用

2018-01-11 15:39 337 查看
  接上一篇博客 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结合实现动画
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: