iOS系统本身提供了两套绘图的框架,即UIBezierPath 和 Core Graphics。使用UIBezierPath可以创建基于矢量的路径,此类是Core Graphics框架关于路径的封装,所以使用起来比较简单。使用此类可以定义简单的形状,如椭圆、矩形或者有多个直线和曲线段组成的形状等。UIBezierPath是CGPathRef数据类型的封装。如果是基于矢量形状的路径,都用直线和曲线去创建。我们使用直线段去创建矩形和多边形,使用曲线去创建圆弧(arc)、圆或者其他复杂的曲线形状。
使用UIBezierPath,你只能在当前上下文中绘图,所以如果你当前处于UIGraphicsBeginImageContextWithOptions函数或drawRect:方法中,你就可以直接使用UIKit提供的方法进行绘图。我们一般使用UIBezierPath都是在重写的drawRect方法中实现。首先我们看UIBezierPath绘图的基本步骤:
UIBezierPath类提供了下面这些类方法创建路径:
+ (instancetype)bezierPath;
+ (instancetype)bezierPathWithRect:(CGRect)rect;
+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius;
+ (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)bezierPath;
这个方法适用的范围比较广,适用此方法我们可以根据我们的的需要画出任意的图形。
+ (instancetype)bezierPathWithRect:(CGRect)rect;
这个方法根据传入的Rect参数画出一个矩形
+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
这个方法根据一个矩形画内切的曲线,一般我们用它来画圆或者椭圆
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius;
+ (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;
这个方法用于画弧线,center:弧线中心点的坐标 radius:弧线所在圆的半径 startAngle:弧线开始的角度 endAngle:弧线结束的角度 clockwise: 是否顺时针画弧线(YES表示顺时针 NO表示逆时针)
下面通过几段代码做个事例(注意下面代码都在- (void)drawRect:(CGRect)rect方法中实现)
//绘制三角形
- (void)drawTriangle{
//1. 创建UIBezierPath对象
UIBezierPath *path = [UIBezierPath bezierPath];
//2. 配置属性
[[UIColor yellowColor] setFill]; //设置填充颜色
[[UIColor redColor] setStroke]; //设置描边颜色
path.lineWidth = 3; //设置线宽
//3.添加路径
[path moveToPoint:CGPointMake(160, 100)];
[path addLineToPoint:CGPointMake(100, 220)];
[path addLineToPoint:CGPointMake(220, 220)];
[path closePath]; //闭合路径(也可通过-addLineToPoint:方法添加)
//4.渲染,完成绘制
[path stroke];
[path fill];
}
//矩形
- (void)drawRectPath {
//1. 创建UIBezierPath对象并指定路径
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(60, 100, 200, 100)];
//2. 配置属性
[[UIColor yellowColor] setFill]; //设置填充颜色
[[UIColor redColor] setStroke]; //设置描边颜色
path.lineWidth = 3; //设置线宽
/*
设置线条拐角样式
typedef CF_ENUM(int32_t, CGLineCap) {
kCGLineCapButt, //默认
kCGLineCapRound, //圆角
kCGLineCapSquare //方形
};
*/
path.lineCapStyle = kCGLineCapRound;
/*
两条线连结点的样式
typedef CF_ENUM(int32_t, CGLineJoin) {
kCGLineJoinMiter, //默认:斜接
kCGLineJoinRound, //圆滑衔接
kCGLineJoinBevel //圆滑衔接
};
*/
path.lineJoinStyle = kCGLineJoinBevel;
//3. 渲染,完成绘制
[path stroke];
[path fill];
}
//椭圆
- (void)drawCiclePath {
// 当传入参数为正方形时,绘制出的内切图形就是圆,为矩形时画出的就是椭圆
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(60, 100, 200,300)];
//配置属性
[[UIColor yellowColor] setFill]; //设置填充颜色
[[UIColor redColor] setStroke]; //设置描边颜色
path.lineWidth = 3; //设置线宽
//渲染
[path stroke];
[path fill];
}
效果图:
- (void)drawRoundedRectPath {
//创建带圆角的矩形 圆角半径:20
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(60, 100, 200, 200) cornerRadius:20];
//创建可以指定圆角位置的矩形
//第一个参数一样是传了个矩形
//第二个参数是指定在哪个方向画圆角
//第三个参数是一个CGSize类型,用来指定水平和垂直方向的半径的大小
//UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(60, 100, 200, 200) byRoundingCorners:UIRectCornerTopLeft cornerRadii:CGSizeMake(20, 20)];
//配置属性
[[UIColor yellowColor] setFill]; //设置填充颜色
[[UIColor redColor] setStroke]; //设置描边颜色
path.lineWidth = 3; //设置线宽
//渲染
[path stroke];
[path fill];
}
使用UIBeizerPath画弧线我们需要了解画弧线的参考系:
//画弧线
- (void)drawARCPath {
//CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; 角度转弧度
CGPoint center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:100 startAngle:0 endAngle:DegreesToRadians(100) clockwise:YES];
path.lineCapStyle = kCGLineCapRound;
path.lineJoinStyle = kCGLineJoinRound;
path.lineWidth = 5.0;
UIColor *strokeColor = [UIColor redColor];
[strokeColor set];
[path stroke];
}
我们要明确一点,画弧参数startAngle和endAngle使用的是弧度,而不是角度,因此我们需要将常用的角度转换成弧度。对于效果图中,我们设置弧的中心为控件的中心,起点弧度为0,也就是正东方向,而终点是135度角的位置。如果设置的clockwise:YES是逆时针方向绘制,如果设置为NO,效果如下:
说到画二次贝塞尔曲线那就必须要说控制点了,首先我们看下面的图片:
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
参数说明:
endPoint:终端点
controlPoint:控制点,对于二次贝塞尔曲线,只有一个控制点
- (void)drawSecondBezierPath {
// 创建路径对象
UIBezierPath *path = [UIBezierPath bezierPath];
// 设置起始点,终点和控制点的位置
CGPoint startPoint = CGPointMake(20, 200);
CGPoint endPoint = CGPointMake(300, 200);
CGPoint controlPoint = CGPointMake(100, 400);
// 设置起始点位置
[path moveToPoint:startPoint];
// 添加二次曲线
[path addQuadCurveToPoint:endPoint controlPoint:controlPoint];
path.lineCapStyle = kCGLineCapRound;
path.lineJoinStyle = kCGLineJoinRound;
path.lineWidth = 5.0;
UIColor *strokeColor = [UIColor redColor];
[strokeColor set];
[path stroke];
}
效果图:
贝塞尔曲线必定通过首尾两个点,称为端点;中间两个点虽然未必要通过,但却起到牵制曲线形状路径的作用,称作控制点。关于三次贝塞尔曲线的控制器,看下图:
如下方法就是画三次贝塞尔曲线的关键方法,以三个点画一段曲线,一般和-moveToPoint:配合使用。
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
实现代码:
//画三次塞贝尔曲线
- (void)drawThirdBezierPath { UIBezierPath *path = [UIBezierPath bezierPath]; // 设置起始端点 [path moveToPoint:CGPointMake(20, 150)]; [path addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(160, 0) controlPoint2:CGPointMake(160, 250)]; path.lineCapStyle = kCGLineCapRound;
path.lineJoinStyle = kCGLineJoinRound;
path.lineWidth = 5.0;
UIColor *strokeColor = [UIColor redColor];
[strokeColor set];
[path stroke];
}
效果图:
我们可以通过两个控制点的坐标控制曲线的弯曲度,如果两个控制点的纵坐标和两个端点在同一水平线上,那么画出的就是一条直线了。
源代码在我的github网站(https://github.com/cokeduo/UIBezierPath-)有需要的小伙伴可以下载。