在做业务需求的通常会有一些异形图片,我们通常会使用CAShaperLayer来绘制这些图形,因为他比较简单且易维护,但是有时候会遇到一些bezierPath的动画,这个时候往往就会出现各种奇怪的动画效果,比如美团外卖的tab,如果为了快速完成需求,可以直接用lottie实现,可是身为iOSer,总是希望可以用原生实现这样的功能。
接下来我们就用代码实现这个功能,首先画个路径:
CGFloat height = 100;
NSInteger itemCount = 5;
CGFloat itemWidth = [UIScreen width]/itemCount;
CGFloat topSpace = 25;
CGFloat s = 82.945 / 180.0 * M_PI;
__block CAShapeLayer *layer1;
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(0, topSpace)];
[bezierPath addLineToPoint:CGPointMake(itemWidth * 2 - 3.5, topSpace)];
[bezierPath addArcWithCenter:CGPointMake([UIScreen width]/2, topSpace + 3.5) radius:28.5 startAngle:(3 * M_PI_2 - s) endAngle: (M_PI_2 * 3 + s) clockwise:YES];
[bezierPath addLineToPoint:CGPointMake([UIScreen width], topSpace)];
[bezierPath addLineToPoint:CGPointMake([UIScreen width], height)];
[bezierPath addLineToPoint:CGPointMake(0, height)];
[bezierPath addLineToPoint:CGPointMake(0, topSpace)];
CAShapeLayerCreate().makeChain.frame(CGRectMake((0) /2, ([UIScreen height] - 200) /2, [UIScreen width], 200))
.shadowColor([UIColor blackColor].CGColor)
.shadowRadius(4)
.path(bezierPath.CGPath)
.lineWidth(1)
.fillColor([UIColor yellowColor].CGColor)
.borderColor(UIColor.redColor.CGColor)
.borderWidth(1)
.strokeColor(UIColor.blackColor.CGColor)
.backgroundColor([UIColor clearColor].CGColor)
.addToSuperLayer(self.view.layer)
.assignTo(^(__kindof CALayer * _Nonnull layer) {
layer1 = layer;
});
然后画个动画后的路径:
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(0, topSpace)];
[bezierPath addLineToPoint:CGPointMake(itemWidth * 2 - 3.5, topSpace)];
[bezierPath addLineToPoint:bezierPath.currentPoint];
[bezierPath addLineToPoint:CGPointMake([UIScreen width]/2, topSpace)];
[bezierPath addLineToPoint:CGPointMake(itemWidth * 3 + 3.5, topSpace)];
[bezierPath addLineToPoint:CGPointMake([UIScreen width], topSpace)];
[bezierPath addLineToPoint:CGPointMake([UIScreen width], height)];
[bezierPath addLineToPoint:CGPointMake(0, height)];
[bezierPath addLineToPoint:CGPointMake(0, topSpace)];
接下来添加一个动画:
CASpringAnimation *animated = [CASpringAnimation animationWithKeyPath:@"path"];
animated.fromValue = (id)(layer1.path);
animated.toValue = (id)(bezierPath.CGPath);
animated.removedOnCompletion = NO;
animated.fillMode = kCAFillModeForwards;
animated.duration = 1;
animated.mass = 1;
[layer1 addAnimation:animated forKey:@"path"];
接下来我们就可以看到这个动画的效果了:
好吧,我承认跟lottie的还是有点差距,不过我想说的是当一个不规则path向规则path做动画的时候其实更多地是保持path段的一致性,不一致就会发生错乱动画,比如之前的突起形状有7段,而方形有9段,这是因为如果我们打断点看这个path,会发现:
在实际的path中,
addArcWithCenter:
会向path添加两段,当他们的段数一样的话,用动画来过度就会表现的非常平滑。