iOS绘图:UIBezierPath
背景
提起iOS绘图,大家可能觉得离自己远。但是我们平时总会遇到给一个view 的某个角加一个圆角,或者需要一个小的三角形。这个时候就离不开今天的话题了:UIBezierPath。
基础
首先明确的是这个类可以画直线和曲线的组合,也就是:任意的组合线条和线条构成的图形。UIBezierPath有一些基础。我们先看看:
曲线定义
形状定义分为两步:
- 使用此类应该先指定路径的几何图形。路径可以定义单纯的线条,或者是线条包含的形状。例如简单的矩形、椭圆和圆弧,也可以定义包含直线段和曲线段混合的复杂多边形。
- 定义形状后,可以使用此类的其他方法在当前图形上下文中渲染路径。
定义线条的过程中,我们可以使用系统提供的便利方法:
+ (instancetype)bezierPathWithRect:(CGRect)rect;
- 这用来创建并返回具有矩形路径的新Bézier路径对象。
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;
- 创建并返回一个新的Bézier路径对象,该对象的矩形路径在指定的角处圆角。
+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
- 创建并返回一个新的具有圆弧的Bézier路径对象。
上述的这三种方法基本涵盖了我们日常的需求 比如绘制一个自定义矩形边,绘制一个带圆角的矩形边,绘制一段圆弧。如果大家的需求是这三种,建议使用这些方法。简单又快捷。
那么实际过程我们可以并不局限于这几个图形样式。例如假设我们需要画一个三角形这个时候怎么办呢?那就需要了解一下曲线的构成了
曲线的绘制
整个线条的绘制方法如官方文档所说:是通过操纵路径的当前点来设置路径的几何图形。
什么意思呢?想像我们有一张纸、一支笔,如果我们要画任何图案,我们定然是通过移动画笔来绘制,那么画笔与纸的接触点就是当前点。
下面我们以实际用画笔画画的例子来讲一下基础的绘制流程:
任何一副画都有起笔,也就是画到纸上的第一个点。在UIBezierPath中,我们通过创建新的空路径对象实现拿起画笔的操作,接下来必须显式设置第一个点。这可以调用如下函数实现
- (void)moveToPoint:(CGPoint)point;
这样我们的起笔就算好了,接下来我们要继续画了。
- 如果我们要画一条直线。那么我们只需要将笔移动到某个点就可以,这需要使用如下函数
- (void)addLineToPoint:(CGPoint)point;
- 如果我们要画一条曲线。那么我们需要告诉系统通过什么样的路径将笔移动到某个点,这需要使用如下函数
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:
(CGPoint)controlPoint2;
- 如果我们要画一个圆弧。那可以使用如下函数
- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
提示:添加新线段的方法始终假定从当前点开始,到指定的某个新点结束。 这就好比我们总是把画笔放在纸上没有拿起来一样,这样我们画的每段线就是首尾相连的。(如果需要拿起画笔,也就是重新从某个点来绘制接下来的画图那么我们可以使用moveToPoint:函数)
之后,我们可以使用任意多的添加线段的方法来不断绘制我们需要的图案。
当我们绘制完成最后一个线段的时候,我们可以选择调用- (void)closePath;方法来闭合某个子路径。
什么是闭合呢?就是将画面上的两个点连接起来,使得两个点之间有一条找不到头和尾的曲线,例如圆,椭圆。一条或两条线段不能组成闭合曲线,至少三条线段才能组成闭合曲线,例如:三角形。
当我们在绘制的过程中调用了moveToPoint:函数,我们的曲线就是不闭合的,这个时候我们调用- (void)closePath就会在子路径首尾之间添加一个从当前点到子路径第一个点的直线段。
当然我们也可以选择不闭合这个子路径,一个Bézier路径对象可以包含任意数量的打开或关闭的子路径。
提示:尽管一个路径中包含多个路径,Bézier路径对象的子路径共享相同的图形属性,并且必须作为一个组进行操作。
曲线属性设置
基本的属性有以下几个:
- lineWidth
路径的线宽。 - lineCapStyle
笔划路径端点的形状。 - lineJoinStyle
绘制路径的连接段之间的接头形状。
绘制
当我们定义了对应的路径后,我们就需要开始绘制了,首先我们需要设置绘制属性
设置绘制属性
绘制的属性是属于某个具体的layer 的。因为我们是在绘图,所以这个layer我们会选择CAShapeLayer,我们可以通过如下方式设置绘制颜色。
Layer.fillColor = UIColor.clear.cgColor
Layer.strokeColor = UIColor.white.cgColor
绘制图案
绘制有两种方法:一种是使用笔划另一种是使用填充方法在当前图形上下文中绘制路径。
使用笔划绘制的是一些线条,使用填充绘制的是线条构成的闭合区域。
使用笔划绘制会用当前笔划颜色和Bézier路径对象的属性绘制路径的轮廓,需要调用:
- (void)stroke;
使用填充绘制会用当前填充颜色和Bézier路径对象的属性绘制图形,需要调用:
- (void)fill;
应用绘制图案
当我们设置好了路径和绘制属性之后,我们需要将路径绘制在某个画布上,也就是我们的CAShapeLayer,通过如下方式将路径加到layer上:
Layer.path= [UIBezierPath bezierPathWithRect:borderLayer.bounds].CGPath;
这样我们就得到了一个带有图案的layer
之后为了展示出来,我们需要将这个layer加在某个view的layer上
View.layer.addSublayer(Layer)
至此我们基本的画图就完了。
详细进阶
在绘制图案的时候我们有时会选择绘制一个圆弧,例如通过如下方法
bezierPathWithArcCenter:radius:startAngle:endAngle:clockwise:
那么这个时候,整个圆弧的绘制起点在第一象限和第四象限的分界线上。而角度是按照顺时针方向增加的,也就是第三象限和第四象限的分界线就是兀/2。以此类推,而我们可以通过clockwise参数来控制是顺时针画线还是逆时针画线。注意⚠️:不是控制角度的增加方向。
结尾
基本的介绍到这里了,希望大家代码写的开心。