http://www.cocoachina.com/ios/20160214/15251.html
CAShapeLayer 是 CALayer 的子类,但是比 CALayer 更灵活,可以画出各种图形,当然,你也可以使用其他方式来画,随你。
杂谈
在 CAShapeLayer 中,也可以像 CALayer 一样指定它的 frame 来画,就像这样:
1
2
3
4
5
|
let layer = CAShapeLayer() layer.frame = CGRectMake(110, 100, 150, 100) layer.backgroundColor = UIColor.blackColor().CGColor view.layer.addSublayer(layer) |
然后你就会得到如图这样的黑色矩形
但是,CAShapeLayer 有一个神奇的属性 path 用这个属性配合上 UIBezierPath 这个类就可以达到超神的效果。
UIBezierPath 顾名思义,这是用贝塞尔曲线的方式来构建一段弧线,你可以用任意条弧线来组成你想要的形状,比如,你想用它来和上面一样画一个矩形,那就可以这样子来做:
1
2
3
4
5
|
let path = UIBezierPath(rect: CGRectMake(110, 100, 150, 100)) let layer = CAShapeLayer() layer.path = path.CGPath layer.fillColor = UIColor.blackColor().CGColor view.layer.addSublayer(layer) |
要注意的是,这里就不要用backgroundColor 这个属性了,而要使用 fillColor 和 strokeColor ,前者代表设置这个 Layer 的填充色,后者代表设置它的边框色
1
2
|
layer.fillColor = UIColor.clearColor().CGCo lorlayer.strokeColor = UIColor.blackColor().CGColor |
可以试一下把上面代码设置颜色的部分改成这个样子,那么运行程序的时候就会是这种样子
玩一下UIBezierPath
在说回 UIBezierPath ,在 UIBezierPath 的 init 方法中,就有很多方便你画各种图形的方法,比如你可以画一个带圆角的图形
1
2
3
4
5
|
let path = UIBezierPath(roundedRect: CGRectMake(110, 100, 150, 100), cornerRadius: 50) let layer = CAShapeLayer() layer.path = path.CGPath layer.fillColor = UIColor.clearColor().CGColor layer.strokeColor = UIColor.blackColor().CGColor |
还可以指定起始角和半径画圆
1
2
3
4
5
6
7
8
|
let radius: CGFloat = 60.0 let startAngle: CGFloat = 0.0 let endAngle: CGFloat = CGFloat(M_PI * 2) let path = UIBezierPath(arcCenter: view.center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true )
let layer = CAShapeLayer() layer.path = path.CGPath layer.fillColor = UIColor.clearColor().CGColor layer.strokeColor = UIColor.blackColor().CGColor |
在这里涉及到角度的问题,起始角和结束角,这里的角度使使用弧度制来表示,这里我收藏了一张图片,以方便参考。
怎么画曲线
贝塞尔曲线的画法是由起点、终点、控制点三个参数来画的,为了解释清楚这个点,我写了几行代码来解释它
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
let startPoint = CGPointMake(50, 300) let endPoint = CGPointMake(300, 300) let controlPoint = CGPointMake(170, 200) let layer1 = CALayer() layer1.frame = CGRectMake(startPoint.x, startPoint.y, 5, 5) layer1.backgroundColor = UIColor.redColor().CGColor let layer2 = CALayer() layer2.frame = CGRectMake(endPoint.x, endPoint.y, 5, 5) layer2.backgroundColor = UIColor.redColor().CGColor let layer3 = CALayer() layer3.frame = CGRectMake(controlPoint.x, controlPoint.y, 5, 5) layer3.backgroundColor = UIColor.redColor().CGColor let path = UIBezierPath() let layer = CAShapeLayer() path.moveToPoint(startPoint) path.addQuadCurveToPoint(endPoint, controlPoint: controlPoint) layer.path = path.CGPath layer.fillColor = UIColor.clearColor().CGColor layer.strokeColor = UIColor.blackColor().CGColor view.layer.addSublayer(layer) view.layer.addSublayer(layer1) view.layer.addSublayer(layer2) view.layer.addSublayer(layer3) |
我很随意的定义了三个点,为了清楚显示它们的位置,我放了三个矩形在上面以便观察,然后调用 path.moveToPoint(startPoint) 让它移动到起始点,然后调用path.addQuadCurveToPoint(endPoint, controlPoint: controlPoint) 这个方法告诉它结束点和控制点,这样它就能画出一条有弧度的线条了,如果把fillColor设置一个颜色,那么它就会变成一个很丑的形状了,示例图如下
控制点决定了它的曲率,曲线的顶点不等于控制点的位置,具体可以看一下贝塞尔曲线的定义,你还可以使用两个控制点来画,两个控制点可以使用方法 path.addCurveToPoint(endPoint, controlPoint1: controlPoint, controlPoint2: controlPoint2)来搞定
这样它会是这个样子
再来说说 CAShapeLayer
CAShapeLayer 是个神奇的东西,给它一个path它就能变成你想要的形状,它还有很多可以玩的地方。综合使用可以组合成不同的动画,比如下面这样
demo1.gif
demo2.gif
demo3.gif
这三个动画就是使用了 strokeEnd、strokeStart和lineWidth 三个属性,第一个动画用了strokeEnd这个属性的值范围是0-1,动画显示了从0到1之间每一个值对这条曲线的影响,strokeStart的方法则是相反的,如果把这两个值首先都设置成0.5然后慢慢改变成0和1的时候就会变成第二个动画,配合lineWidth则曲线会慢慢变粗,这里的很多属性都是支持动画的。
示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
private func animation1() { let animation = CABasicAnimation(keyPath: "strokeEnd" )
animation.fromValue = 0
animation.toValue = 1
animation.duration = 2
layer.addAnimation(animation, forKey: "" )
}
private func animation2() {
layer.strokeStart = 0.5
layer.strokeEnd = 0.5
let animation = CABasicAnimation(keyPath: "strokeStart" )
animation.fromValue = 0.5
animation.toValue = 0
animation.duration = 2
let animation2 = CABasicAnimation(keyPath: "strokeEnd" )
animation2.fromValue = 0.5
animation2.toValue = 1
animation2.duration = 2
layer.addAnimation(animation, forKey: "" )
layer.addAnimation(animation2, forKey: "" )
}
private func animation3() {
let animation = CABasicAnimation(keyPath: "lineWidth" )
animation.fromValue = 1
animation.toValue = 10
animation.duration = 2
layer.addAnimation(animation, forKey: "" )
}
|
应用一下
前一阵子在仿时光网这个APP,其中有一个Layer的形状很怪异,是这样的
很明显它可以用 CAShapeLayer + UIBezierPath 来做,思路大概是这样,先移动到左上方的位置,然后向下划线,然后往右划线,然后往上划线,还剩一个盖子,这个盖子就用一个控制点控制曲率,非常简单,代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
|
let finalSize = CGSizeMake(CGRectGetWidth(view.frame), 400) let layerHeight = finalSize.height * 0.2 let layer = CAShapeLayer() let bezier = UIBezierPath() bezier.moveToPoint(CGPointMake(0, finalSize.height - layerHeight)) bezier.addLineToPoint(CGPointMake(0, finalSize.height - 1)) bezier.addLineToPoint(CGPointMake(finalSize.width, finalSize.height - 1)) bezier.addLineToPoint(CGPointMake(finalSize.width, finalSize.height - layerHeight)) bezier.addQuadCurveToPoint(CGPointMake(0,finalSize.height - layerHeight), controlPoint: CGPointMake(finalSize.width / 2, (finalSize.height - layerHeight) - 40))
layer.path = bezier.CGPath layer.fillColor = UIColor.blackColor().CGColor view.layer.addSublayer(layer) |
就能画出这样的形状来
再来一个复杂点的,微信下拉拍小视频的那只眼睛很有趣,来模仿一下那个效果吧,它是这样的
首先你得画出这只眼睛,这是眼睛包括5个部分组成(这个是用OC写的)
1
2
3
4
5
|
@property (strong, nonatomic) CAShapeLayer *eyeFirstLightLayer; @property (strong, nonatomic) CAShapeLayer *eyeSecondLightLayer; @property (strong, nonatomic) CAShapeLayer *eyeballLayer; @property (strong, nonatomic) CAShapeLayer *topEyesocketLayer; @property (strong, nonatomic) CAShapeLayer *bottomEyesocketLayer; |
然后,还是通过 UIBezierPath 和 CAShapeLayer 这样的老套路来画,代码较多
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
- (CAShapeLayer *)eyeFirstLightLayer { if (!_eyeFirstLightLayer) {
_eyeFirstLightLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center
radius:CGRectGetWidth(self.frame) * 0.2
startAngle:(230.f / 180.f) * M_PI
endAngle:(265.f / 180.f) * M_PI
clockwise:YES];
_eyeFirstLightLayer.borderColor = [UIColor blackColor].CGColor;
_eyeFirstLightLayer.lineWidth = 5.f;
_eyeFirstLightLayer.path = path.CGPath;
_eyeFirstLightLayer.fillColor = [UIColor clearColor].CGColor;
_eyeFirstLightLayer.strokeColor = [UIColor whiteColor].CGColor;
}
return _eyeFirstLightLayer;
} - (CAShapeLayer *)eyeSecondLightLayer { if (!_eyeSecondLightLayer) {
_eyeSecondLightLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center
radius:CGRectGetWidth(self.frame) * 0.2
startAngle:(211.f / 180.f) * M_PI
endAngle:(220.f / 180.f) * M_PI
clockwise:YES];
_eyeSecondLightLayer.borderColor = [UIColor blackColor].CGColor;
_eyeSecondLightLayer.lineWidth = 5.f;
_eyeSecondLightLayer.path = path.CGPath;
_eyeSecondLightLayer.fillColor = [UIColor clearColor].CGColor;
_eyeSecondLightLayer.strokeColor = [UIColor whiteColor].CGColor;
}
return _eyeSecondLightLayer;
} - (CAShapeLayer *)eyeballLayer { if (!_eyeballLayer) {
_eyeballLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center
radius:CGRectGetWidth(self.frame) * 0.3
startAngle:(0.f / 180.f) * M_PI
endAngle:(360.f / 180.f) * M_PI
clockwise:YES];
_eyeballLayer.borderColor = [UIColor blackColor].CGColor;
_eyeballLayer.lineWidth = 1.f;
_eyeballLayer.path = path.CGPath;
_eyeballLayer.fillColor = [UIColor clearColor].CGColor;
_eyeballLayer.strokeColor = [UIColor whiteColor].CGColor;
_eyeballLayer.anchorPoint = CGPointMake(0.5, 0.5);
}
return _eyeballLayer;
} - (CAShapeLayer *)topEyesocketLayer { if (!_topEyesocketLayer) {
_topEyesocketLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, CGRectGetHeight(self.frame) / 2)];
[path addQuadCurveToPoint:CGPointMake(CGRectGetWidth(self.frame), CGRectGetHeight(self.frame) / 2)
controlPoint:CGPointMake(CGRectGetWidth(self.frame) / 2, center.y - center.y - 20)];
_topEyesocketLayer.borderColor = [UIColor blackColor].CGColor;
_topEyesocketLayer.lineWidth = 1.f;
_topEyesocketLayer.path = path.CGPath;
_topEyesocketLayer.fillColor = [UIColor clearColor].CGColor;
_topEyesocketLayer.strokeColor = [UIColor whiteColor].CGColor;
}
return _topEyesocketLayer;
} - (CAShapeLayer *)bottomEyesocketLayer { if (!_bottomEyesocketLayer) {
_bottomEyesocketLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, CGRectGetHeight(self.frame) / 2)];
[path addQuadCurveToPoint:CGPointMake(CGRectGetWidth(self.frame), CGRectGetHeight(self.frame) / 2)
controlPoint:CGPointMake(CGRectGetWidth(self.frame) / 2, center.y + center.y + 20)];
_bottomEyesocketLayer.borderColor = [UIColor blackColor].CGColor;
_bottomEyesocketLayer.lineWidth = 1.f;
_bottomEyesocketLayer.path = path.CGPath;
_bottomEyesocketLayer.fillColor = [UIColor clearColor].CGColor;
_bottomEyesocketLayer.strokeColor = [UIColor whiteColor].CGColor;
}
return _bottomEyesocketLayer;
} |
然后更改一下某些属性的值,方便稍后的动画
1
2
3
4
5
6
7
8
|
- (void)setupAnimation { self.eyeFirstLightLayer.lineWidth = 0.f;
self.eyeSecondLightLayer.lineWidth = 0.f;
self.eyeballLayer.opacity = 0.f;
_bottomEyesocketLayer.strokeStart = 0.5f;
_bottomEyesocketLayer.strokeEnd = 0.5f;
_topEyesocketLayer.strokeStart = 0.5f;
_topEyesocketLayer.strokeEnd = 0.5f;}
|
最后根据 UIScrollView 的 contentOffset 来控制各种属性,办法较笨,但管用。
最后
总之使用 UIbezierPath 和 CAShapeLayer 可以画出你想要的任何形状,没有它做不到,只有你想不到,搞定了它们你就可以轻松定制你想要的任何控件了。
相关推荐
UIBezierPath和CAShapeLayer绘图。UIBezierPath类允许你在自定义的View中绘制和渲染由直线和曲线组成的路径。你可以在初始化的时候,直接为你的UIBezierPath指定一个几何图形。 路径可以是简单的几何图形例如: 矩形...
在iOS开发中,UIBezierPath和CAShapeLayer是两种强大的工具,它们可以帮助开发者创建复杂的图形和动画效果。本文将深入探讨如何使用它们来实现镂空和遮罩效果,这两种效果在用户界面设计中非常常见,可以增加应用的...
本篇将详细讲解如何使用`UIBezierPath`和`CAShapeLayer`在Swift中自定义一款倒计时进度条,该进度条适用于启动页面的倒计时功能,可以灵活定制颜色、宽度以及响应点击事件。 首先,`UIBezierPath`是`UIKit`框架中的...
来源: Licence: MIT 作者: UIBezierPath和CAShapeLayer画图,这个DEMO展示了如何使用贝塞尔曲线画出了各种图形,包括叮当猫
在iOS开发中,UIBezierPath和CAShapeLayer是两种常用的技术,用于在屏幕上绘制自定义图形。本篇文章将深入探讨这两个关键概念,并通过一个实际的例子——绘制哆啦A梦的简单形状,来阐述它们的应用。 首先,...
通过上述步骤,你就可以熟练地使用`CAShapeLayer` 和贝塞尔曲线创建各种动态的圆形UI视图了。在实际项目中,你可以根据需求调整动画参数,如速度、颜色、透明度等,创造出更丰富的视觉效果。同时,`CAShapeLayer` 也...
这个“ios-用CAShapeLayer画成的饼状图.zip”项目就提供了一个使用Core Animation的CAShapeLayer来绘制饼状图的示例。下面将详细介绍如何利用CAShapeLayer进行饼状图的绘制以及实现点击交互。 首先,CAShapeLayer是...
描述中提到的"尝试用UIBezierPath和CAShapeLayer画一个环形圆",实际上可能涉及以下步骤: 1. 创建UIBezierPath实例,使用`addArcWithCenter:radius:startAngle:endAngle:clockwise:`方法添加圆弧路径。 2. 设置...
因此,使用CAShapeLayer和UIBezierPath组合,可以在不涉及drawRect:方法的情况下实现高效的图形绘制。 UIBezierPath与Core Graphics的关系则体现在它们在图形绘制上的共性和互补性。UIBezierPath可以看作是Core ...
CAShapeLayer的优势在于它能以极低的内存占用和高效的性能绘制复杂的图形,同时支持硬件加速。 虚线绘制通常用于表示非连续的线条,例如进度条、分割线等。在CAShapeLayer中,我们可以通过设置strokeColor、...
在iOS开发中,UIBezierPath是一个非常重要的类,它属于UIKit框架,主要用于绘制矢量图形和路径。UIBezierPath是Core Graphics(也称为Quartz 2D)的一部分,允许开发者创建自定义形状,进行复杂的绘图操作,以及与...
CAShapeLayer是Core Animation框架中的一个关键类,用于在iOS和macOS平台上创建基于路径的图形。它允许开发者创建复杂的2D形状,并且可以对这些形状进行动画化处理,提供了非常丰富的视觉效果。在这个名为...
本示例“ios-波浪效果的实现.zip”提供了一个使用CAShapeLayer和UIBezierPath实现波浪动画的实践案例,这主要涉及到iOS图形绘制和动画的知识点。下面将详细讲解如何利用这两个核心组件来构建波浪效果。 首先,...
在Swift编程中,CAShapeLayer是一个非常强大的工具,它允许开发者创建复杂的图形和动画效果,而不必直接操作像素。在本教程中,我们将探讨如何利用CAShapeLayer来封装一个具有动画效果的按钮。首先,我们需要了解...
在iOS开发中,UI设计经常需要创建具有复杂形状的视图,例如,一个视图中间需要挖去一部分形成镂空效果。...理解并熟练掌握`CAShapeLayer`和`mask`的使用,对于iOS开发者来说是至关重要的技能之一。
一旦获取到中心点,我们可以使用`UIBezierPath`画一个小圆表示圆心,并显示坐标信息。坐标通常是指图形相对于画布视图的左下角的(x, y)位置,可以利用`CGAffineTransform`进行坐标转换。 此外,为了存储和恢复用户...
总的来说,"CAShapeLayer动画"案例展示了如何结合使用CAShapeLayer、UIBezierPath、CAAnimation和手势识别来创建一个互动且富有视觉吸引力的iOS应用效果。开发者可以通过学习此案例,进一步提升自己在iOS图形绘制和...
总之,这个"IOS应用源码之相机+画板"项目涵盖了iOS开发中的多个核心知识点,包括多媒体处理(AVFoundation)、用户界面交互(UIKit)、图形绘制(UIBezierPath、CAShapeLayer)以及图像处理(CoreGraphics、Core...
首先,CAShapeLayer是CALayer的一个子类,专门用于绘制基于路径(Path)的图形。它允许开发者自定义复杂的形状,并对其进行动画处理。在圆环百分比动画中,我们通常需要创建一个UIBezierPath对象来表示圆环的路径,...
除了内置的动画方法,我们还可以利用UIBezierPath和CAShapeLayer来创建自定义动画,例如,模拟文字沿着路径移动的效果。首先绘制一个路径,然后让UILabel的layer追踪这个路径: ```swift let path = UIBezierPath()...