CAShapeLayer 是什么?
CAShapeLayer 是一个继承自 CALayer 的一个子Layer。
![](https://img.haomeiwen.com/i2701794/f003b98b07120462.png)
为什么有了 CALayer 之后,还要有一个 CAShapeLayer ? 有什么优势吗?
我们都知道 CALayer,是 UIView 内部一个用于显示的容器。
那 CAShapeLayer 作为另外的一种 Layer,出现的目的是什么的?
个人理解:CAShapeLayer,作为一个 CALayer 它隔离了和 UIView 的强联系。
可以单独的拿过来用。
那仅仅只有这么一点,我们也可以自定义 CALayer 出来用啊。
CAShapeLayer 有一个特别好用的属性,
path
。我们可以里用UIBezierPath
&CAShapeLayer
的.path
属性,画出我们任意希望显示的图形。并且搭配 CAShapeLayer 的strokeBegin
&strokeEnd
属性。可以做出一些比较炫酷的图形动画效果。
![](https://img.haomeiwen.com/i2701794/d96d2a6c57592968.png)
CAShapeLayer 的基本使用。
由于 CAShapeLayer
是继承自 CALayer
的,那么 CALayer
可以咋用,CAShapeLayer
就可以咋用。
/**
1. CAShaperLayer : CALayer.
2. CALayer 是可以做动画的,所以 CAShapeLayer 也可以做动画。
3. CAShapeLayer 是 CALayer ,不是 UIView 所以,不能接受事件。
*/
- (void)cashapeLayer {
CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
shapeLayer.frame = CGRectMake(0, 64, 200, 200);
// 和背景色不冲突?
shapeLayer.backgroundColor = [UIColor orangeColor].CGColor;
// 设置描边颜色
shapeLayer.strokeColor = [UIColor blackColor].CGColor;
// 设置填充颜色
shapeLayer.fillColor = [UIColor greenColor].CGColor;
// 发现,这两个属性并没什么乱用。
// 类似于描边、填充等属性,必须作用在路径上。
[self.view.layer addSublayer:shapeLayer];
}
特点注意:虽然 CAShapeLayer 可以使用 CALayer 的那套。但是,如果不搭配 UIBezierPath的话,那么对于大多数 CAShapeLayer 特有的属性来说,都是不起作用的。
CAShapeLayer 搭配 UIBezierPath 来使用。
CAShapeLayer 搭配 UIBezierPath 使用,才是最适合的做法。
我们可以使用 UIBezierPath 绘制出自己需要的图形,并设置到 CAShapeLayer 上,来达到绘制 CAShapeLayer 的目的。
/**
使用路径绘制 CAShape
因为用到了 贝塞尔曲线,所以就可以使用核心绘图的一些参数。
比如,线宽、描边、填充等。
*/
- (void)shapeLayerUserPath {
CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
// 创建路径
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10, 80)];
[path addLineToPoint:CGPointMake(100, 80)];
[path addLineToPoint:CGPointMake(100, 180)];
[path addLineToPoint:CGPointMake(10, 180)];
[path addLineToPoint:CGPointMake(10, 80)];
// [path closePath]; // 闭合路径
// 设置 CAShapeLayer 的绘制路径
shapeLayer.path = path.CGPath;
// 有路径了,就可以设置填充颜色,线的样式,描边颜色等。
shapeLayer.strokeColor = [UIColor purpleColor].CGColor;
// CAShapeLayer 如果是闭合路径,那么默认的填充颜色是黑色。
// shapeLayer.fillColor = [UIColor orangeColor].CGColor;
shapeLayer.fillColor = [UIColor whiteColor].CGColor;
shapeLayer.lineWidth = 10; // 线宽
shapeLayer.lineJoin = @"round"; // 线头样式
shapeLayer.lineCap = @"round"; // 折现结合处样式
[self.view.layer addSublayer:shapeLayer];
}
运行效果:
![](https://img.haomeiwen.com/i2701794/36248aa540a36f6f.png)
当然,UIBezierPath
能够画出什么图形,那么 CAShapeLayer
就能显示出多少中图形。
+ (instancetype)bezierPath;
+ (instancetype)bezierPathWithRect:(CGRect)rect;
+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius; // rounds all corners with the same horizontal and vertical radius
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;
+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
+ (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
// Returns an immutable CGPathRef which is only valid until the UIBezierPath is further mutated.
// Setting the path will create an immutable copy of the provided CGPathRef, so any further mutations on a provided CGMutablePathRef will be ignored.
@property(nonatomic) CGPathRef CGPath;
- (CGPathRef)CGPath NS_RETURNS_INNER_POINTER CF_RETURNS_NOT_RETAINED;
// Path construction
- (void)moveToPoint:(CGPoint)point;
- (void)addLineToPoint:(CGPoint)point;
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise NS_AVAILABLE_IOS(4_0);
- (void)closePath;
一个比较常用使用的场景。
![](https://img.haomeiwen.com/i2701794/ad7065639afb400e.png)
ofo 小黄车的 App 界面,界面的下半部分是一个曲线加一个矩形的样式。
可以利用 CAShapeLayer
& UIBezierPath
来实现这么一个场景。
主要思路:在屏幕中间的地方,画一条曲线即可。
/* |-------------------------------------------------------------------|
| |
| |
| 控制点(controlPoint) |
| |
| |
| 起点(moveToPoint) 终点(toPint) |
-------------------------------------------------------------------
*/
- (void)prepareUI {
CAShapeLayer *layer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
// 画一条贝塞尔曲线
[path moveToPoint:CGPointMake(0, [UIScreen mainScreen].bounds.size.height * 0.5 + 100)];
[path addQuadCurveToPoint:CGPointMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height * 0.5 + 100) controlPoint:CGPointMake(self.view.center.x, self.view.center.y )];
// 设置曲线到 CAShapeLayer 的 path
layer.path = path.CGPath;
// 实现线的基本属性
layer.strokeColor = [UIColor purpleColor].CGColor;
layer.lineWidth = 5;
layer.lineCap = kCALineCapRound;
layer.fillColor = [UIColor whiteColor].CGColor;
[self.view.layer addSublayer:layer];
}
运行效果:
![](https://img.haomeiwen.com/i2701794/5d9bc61caaa55f7f.png)
使用 CAShapeLayer 以动画的方式绘制图形。
由于 CAShapeLayer 继承自 CALayer。CALayer 有可以搭配 CAAnimation 使用。
所以可以使用 CAShapeLayer & UIBezierPath & CAAnimation 来产生比较酷炫的动画效果。
主要是搭配 CAShapeLayer 的 strokeStart & strokeEnd 来实现比较炫酷的效果。
最简单的矩形动画
/**
动画画矩形
*/
- (void)shapeLayerDrawRect {
CAShapeLayer *layer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(10, 200, 100, 100)];
layer.path = path.CGPath;
layer.strokeColor = [UIColor orangeColor].CGColor;
layer.fillColor = [UIColor whiteColor].CGColor;
layer.lineWidth = 3;
layer.lineCap = kCALineCapRound;
[self.view.layer addSublayer:layer];
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
anim.fromValue = @0;
anim.toValue = @1;
anim.repeatCount = MAXFLOAT;
anim.duration = 3;
anim.fillMode = kCAFillModeForwards;
anim.removedOnCompletion = NO;
[layer addAnimation:anim forKey:nil];
}
![](https://img.haomeiwen.com/i2701794/547240b39a563b18.gif)
基本上,你能画出的路径都能做出这些动画。
![](https://img.haomeiwen.com/i2701794/83799c15b3e0ddc6.gif)
可以利用 CAShapeLayer 的动画特性做一些提示类的动画。
由于 CAShapeLayer 不是 UIResponder ,所以,它不能接受事件。
它的作用,就是展示,也仅仅是展示。
可以利用 CAShapeLayer 的路径动画特性,做一些有功能性的动画。
![](https://img.haomeiwen.com/i2701794/972af8d614a8cfc0.gif)
正确对勾动画
/**
先画一个圈,在画一个对勾.
*/
- (void)successClick {
// UIView *view = [[UIView alloc] init];
// view.frame = CGRectMake(0, 0, 40, 40);
// view.center = self.view.center;
// view.backgroundColor = [UIColor blackColor];
// [self.view addSubview:view];
CAShapeLayer *successLayer = [CAShapeLayer layer];
//[view.layer addSublayer:successLayer];
UIBezierPath *layerPath = [UIBezierPath bezierPath];
// 原形 path
UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:self.view.center radius:40 startAngle:-M_PI_2 endAngle:M_PI * 2 - M_PI_2 clockwise:YES];
[layerPath appendPath:path1];
// 对勾 path
UIBezierPath *path2 = [UIBezierPath bezierPath];
[path2 moveToPoint:CGPointMake(self.view.center.x - 40, self.view.center.y)];
// [path2 moveToPoint:CGPointMake(147,334)];
[path2 addLineToPoint:CGPointMake(self.view.center.x, self.view.center.y + 40)];
// [path2 addLineToPoint:CGPointMake(186, 372)];
[path2 addLineToPoint:CGPointMake(self.view.center.x + 40 / 1.4, self.view.center.y - 40 / 1.4)];
//[path2 addLineToPoint:CGPointMake(218,309)];
[layerPath appendPath:path2];
successLayer.path = layerPath.CGPath;
successLayer.strokeColor = [UIColor orangeColor].CGColor;
successLayer.lineCap = kCALineCapRound;
successLayer.lineWidth = 3;
successLayer.fillColor = [UIColor whiteColor].CGColor;
// [view.layer addSublayer:successLayer];
CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
ani.fromValue = @0;
ani.toValue = @1;
ani.repeatCount = 1;
ani.duration = 2;
ani.fillMode = kCAFillModeForwards;
ani.removedOnCompletion = NO;
ani.delegate = self;
[successLayer addAnimation:ani forKey:@"successAni"];
[self.view.layer addSublayer:successLayer];
_successLayer = successLayer;
}
失败的 XX 动画
- (void)failClick {
CAShapeLayer *failLayer = [CAShapeLayer layer];
UIBezierPath *failPathTotal = [UIBezierPath bezierPath];
UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:self.view.center radius:40 startAngle:-M_PI_2 endAngle:M_PI * 2 - M_PI_2 clockwise:YES];
[failPathTotal appendPath:path1];
UIBezierPath *path2 = [UIBezierPath bezierPath];
[path2 moveToPoint:CGPointMake(self.view.center.x - 40 / 1.4, self.view.center.y - 40 / 1.4)];
[path2 addLineToPoint:CGPointMake(self.view.center.x + 40 / 1.4, self.view.center.y + 40 / 1.4)];
[failPathTotal appendPath:path2];
UIBezierPath *path3 = [UIBezierPath bezierPath];
[path3 moveToPoint:CGPointMake(self.view.center.x + 40 / 1.4, self.view.center.y - 40 / 1.4)];
[path3 addLineToPoint:CGPointMake(self.view.center.x - 40 / 1.4, self.view.center.y + 40 / 1.4)];
[failPathTotal appendPath:path3];
failLayer.path = failPathTotal.CGPath;
failLayer.strokeColor = [UIColor orangeColor].CGColor;
failLayer.lineCap = kCALineCapRound;
failLayer.lineWidth = 3;
failLayer.fillColor = [UIColor whiteColor].CGColor;
[self.view.layer addSublayer:failLayer];
CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
ani.fromValue = @0;
ani.toValue = @1;
ani.repeatCount = 1;
ani.duration = 2;
ani.fillMode = kCAFillModeBackwards;
ani.removedOnCompletion = NO;
ani.delegate = self;
[failLayer addAnimation:ani forKey:@"failAni"];
_failLayer = failLayer;
}
核心则是,首先需要把动画需要的几条路径计算出来。
比如,第一个 git 路径包含两部分。
1.一个原形路径
// 圆形 path
UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:self.view.center radius:40 startAngle:-M_PI_2 endAngle:M_PI * 2 - M_PI_2 clockwise:YES];
2.一个折线路径
// 对勾 path
UIBezierPath *path2 = [UIBezierPath bezierPath];
[path2 moveToPoint:CGPointMake(self.view.center.x - 40, self.view.center.y)];
// [path2 moveToPoint:CGPointMake(147,334)];
[path2 addLineToPoint:CGPointMake(self.view.center.x, self.view.center.y + 40)];
// [path2 addLineToPoint:CGPointMake(186, 372)];
[path2 addLineToPoint:CGPointMake(self.view.center.x + 40 / 1.4, self.view.center.y - 40 / 1.4)];
然后把这两个路径添加到另外一个 UIBezierPath 中。
UIBezierPath *layerPath = [UIBezierPath bezierPath];
[layerPath appendPath:path1];
[layerPath appendPath:path2];
(对,UIBezierPath不光可以 add 各种形状,还可以 appendPath:)
![](https://img.haomeiwen.com/i2701794/b473b9ec73fa42af.png)
然后把 layerPath
设置给 CAShapeLayer 即可。
CAShapeLayer.path = layerPath.CGPath;
最后总结
- CAShapeLayer 继承自 CALayer。所以,可以使用 CAAnimation 来做动画。
- CAShapeLayer 有一个 path 属性,可以绘制你能想到的所有的路径。
- CAShapeLayer 搭配 strokeStart & strokeEnd 两个属性,可以做出比较炫酷的动画。
注意点:CAShapeLayer 搭配 UIBezierPath 时,默认的 fillColor 是黑色的。
CAShapeLayer 主要是搭配 UIBezierPath 加上 CAAnimation 配合 strokeStart & strokeEnd 来做出比较炫酷的动画。
由于时间比较仓促,这片文章只是简单的介绍了CAShapeLayer的基本使用。
网友评论