CAShapeLayer Path Animation / 2019-09-27

CAShapeLayer动画时一个小技巧,避免直接赋值path,而使用strokeEnd可以自定义动画效果。

在实际项目开发中,遇到了使用CAShapeLayer绘制圆弧的场景,根据业务进度从0~360度步进式填充圆弧。最开始使用直接修改path的方式:

shapeLayer.path = newPath.CGPath;

根据CAlayer的动画原理可知,此时shapeLayer会有一个隐式动画。CAlayer的隐式动画的一个问题就是动画是线性的,往往达不到我们想要的效果。这个时候就需要我们创建自定义动画。

对于CAShapeLayer来说,想要实现path步进效果的自定义动画,需要借助其strokeStart,strokeEnd属性。

典型的实现方式如下:

//创建CAShapeLayer,填充完整的path,并设置strokeEnd = 0.0
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100.0, 100.0)
		                                                     radius:100.0
		                                                 startAngle:-M_PI_2*3
		                                                   endAngle:M_PI_2
		                                                  clockwise:YES];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.strokeColor = [UIColor redColor].CGColor;
shapeLayer.fillColor = [UIColor clearColor].CGColor;
shapeLayer.lineWidth = 2;
shapeLayer.path = bezierPath.CGPath;
shapeLayer.lineCap = kCALineCapRound;
shapeLayer.strokeStart = 0.0;
shapeLayer.strokeEnd = 0.0;//取值范围0-1
...

[shapeLayer removeAllAnimations];
shapeLayer.strokeEnd = startValue;
  
//添加自定义动画,作用于strokeEnd,并设置动画完成时维持终态
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = 0.7;
animation.fromValue = [NSNumber numberWithFloat:startValue];
animation.toValue = [NSNumber numberWithFloat:endValue];
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[shapeLayer addAnimation:animation forKey:nil];

其它文章

iOS 13中dyld 3的改进和优化
iOS Sign With Apple实践
Address Sanitizer的原理和使用
iOS 13 适配
iOS Asset Catalog and Bundle