UIBezierPath用于定义一个直线/曲线组合而成的路径,并且可以在自定义视图中渲染该路径。
注意:使用UIBezierPath绘画的代码写在自定义视图的drawRect:方法中。
一、创建UIBezierPath.
+ (instancetype)bezierPath;
初始化一个UIBezierPath对象。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
+ (instancetype)bezierPathWithRect:(CGRect)rect;
以CGRect为范围,创建一个矩形路径。
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(100, 100, 200, 300)];
+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
以CGRect为范围,创建一个圆/椭圆。
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 200, 300)];
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius;
以CGRect为大小,以cornerRadius为圆角半径,绘制一个圆角矩形。
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(100, 100, 200, 300) cornerRadius:10.f];
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;
绘制一个圆角矩形,通过UIRectCorner选择圆弧的位置,cornerRadii为圆弧的大小。
注:UIRectCorner的值:
typedefNS_OPTIONS(NSUInteger, UIRectCorner) {
UIRectCornerTopLeft =1<<0, //矩形左上角
UIRectCornerTopRight =1<<1, //矩形右上角
UIRectCornerBottomLeft =1<<2, //矩形左下角
UIRectCornerBottomRight =1<<3, //矩形右下角
UIRectCornerAllCorners = ~0UL //矩形四个角都包括
};
注意:cornerRadii为圆弧半径,圆弧以cornerRadii宽、高的值大的为准,如果超过其邻近最短边的一半,则已最短边一半为准。(自己试出来的)
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(100, 100, 200, 300) byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomLeft cornerRadii:CGSizeMake(20, 40)];
+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
绘制一个圆弧路径。ArcCenter:圆弧圆心位置;radius:圆弧半径;startAngle:开始的弧度(角度);endAngle:结束的弧度(角度);clockwise:是否为顺时针。
注意:iPhone中,左上角为原点,x轴向右为正方向;y轴向下为正方向。
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:self.view.center radius:100 startAngle:M_PI_2 endAngle: 2 * M_PI clockwise:YES];
+ (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;
根据CGPath创建一个新的UIBezierPath。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
UIBezierPath *newPath = [UIBezierPath bezierPathWithCGPath:bezierPath.CGPath];
二、路径操作函数
- (void)moveToPoint:(CGPoint)point;
将当前点移动到指定的位置。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100, 300)];
- (void)addLineToPoint:(CGPoint)point;
在路径中增加一条直线(起点+终点=一条直线)
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100,300)];
[bezierPath addLineToPoint:CGPointMake(150, 150)];
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
绘制三阶贝塞尔曲线。以endPoint为终点,以controlPoint1、controlPoint2两个点为控制点,绘制贝塞尔曲线。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100,300)];
[bezierPath addCurveToPoint:CGPointMake(300, 300) controlPoint1:CGPointMake(150, 150) controlPoint2:CGPointMake(220, 360)];
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
绘制二阶贝塞尔曲线。以endPoint为终点,以controlPoint为控制点,绘制二阶贝塞尔曲线。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100,300)];
[bezierPath addQuadCurveToPoint:CGPointMake(300, 300) controlPoint:CGPointMake(150, 150)];
- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise NS_AVAILABLE_IOS(4_0);
绘制一条圆弧。ArcCenter:圆弧圆心位置;radius:圆弧半径;startAngle:开始的弧度(角度);endAngle:结束的弧度(角度);clockwise:是否为顺时针。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100,300)];
[bezierPath addArcWithCenter:self.view.center radius:100 startAngle:M_PI_2 endAngle:2 * M_PI clockwise:YES];
注:因为圆弧的中心和起点不是一个位置,所以效果图中多了一个从起点到圆弧开始点的直线。
- (void)closePath;
使用一条直线闭合路径的起点和终点, 该方法同时也会更新当前点到新直线的终点(即路径的起点)(使一个路径变成闭合回路)。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100,300)];
[bezierPath addLineToPoint:CGPointMake(150, 50)];
[bezierPath addLineToPoint:CGPointMake(220, 80)];
[bezierPath closePath];
[bezierPath addLineToPoint:CGPointMake(250, 430)];
注:在效果图中可以看出,在调用closePath方法之后,路径形成了一个封闭的三角形,之后再添加直线,也是从起点开始,而不是上一个终点。
- (void)removeAllPoints;
移除路径中所有的点。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath removeAllPoints];
- (void)appendPath:(UIBezierPath *)bezierPath;
路径中增加一个已有路径。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
UIBezierPath *path2 = [UIBezierPath bezierPath];
[bezierPath appendPath:path2];
- (UIBezierPath *)bezierPathByReversingPath NS_AVAILABLE_IOS(6_0);
返回一个翻转已有路径的新路径。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
UIBezierPath*path2 = [bezierPath bezierPathByReversingPath];
- (void)applyTransform:(CGAffineTransform)transform;
对路径中的所有点进行二维形变, 该变化立即生效, 且为永久性改变所有点。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath applyTransform:CGAffineTransformMakeTranslation(20, 20)];
三、路径信息属性
@property(nonatomic) CGPathRef CGPath;
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
CGPathRefpath = bezierPath.CGPath;
@property(readonly,getter=isEmpty) BOOL empty;
是否路径信息为空, 即使通过moveToPoint:移动到指定的位置也算不为空。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
BOOLisEmpty = bezierPath.empty;
@property(nonatomic,readonly) CGRect bounds;
可以封闭所有路径点的最小矩形范围, 包括多次贝塞尔曲线的控制点在内。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
CGRect bounds = bezierPath.bounds;
@property(nonatomic,readonly) CGPoint currentPoint;
路径当前所在点。
UIBezierPath*path = [UIBezierPathbezierPath];
CGPoint currentPoint = path.currentPoint;
- (BOOL)containsPoint:(CGPoint)point;
是否包含指定点。
UIBezierPath*path = [UIBezierPathbezierPath];
BOOL isContainsPoint = [path containsPoint:CGPointMake(20,30)];
四、绘图相关方法和属性
@property(nonatomic) CGFloat lineWidth;
路径的线宽。
UIBezierPath*path = [UIBezierPath bezierPath];
path.lineWidth =10;
@property(nonatomic) CGLineCap lineCapStyle;
路径的终点形状, 该属性适用于开放路径的起点和终点。
注意:lineCapStyle的值:
typedefCF_ENUM(int32_t, CGLineCap) {
kCGLineCapButt, //方形结束, 结束位置正好为精确位置。——默认值
kCGLineCapRound, //圆形结束, 结束位置超过精确位置半个线宽。
kCGLineCapSquare //方形结束, 结束位置超过精确位置半个线宽。
};
UIBezierPath*path = [UIBezierPath bezierPath];
path.lineCapStyle = kCGLineCapButt;
@property(nonatomic) CGLineJoin lineJoinStyle;
路径的连接点(拐角)形状。
注意:lineJoinStyle的值:
typedefCF_ENUM(int32_t, CGLineJoin) {
kCGLineJoinMiter, //全部连接(尖角)。——默认值
kCGLineJoinRound, //圆形连接。(圆角)
kCGLineJoinBevel //斜角连接。(切角)
};
UIBezierPath*path = [UIBezierPath bezierPath];
path.lineJoinStyle = kCGLineJoinMiter;
@property(nonatomic) CGFloat miterLimit; // Used when lineJoinStyle is kCGLineJoinMiter
最大斜接长度,怎么理解呢?就是上图中拐角处外面尖角和内部尖角的距离。但是这个只有在kCGLineJoinMiter情况下使用才有效果,如果这个miterLimit小于斜接长度,就成为了kCGLineJoinBevel类型。
UIBezierPath*path = [UIBezierPath bezierPath];
path.lineJoinStyle = kCGLineJoinMiter;
path.miterLimit = 1; ////这里设为1 因为斜接长度超过了1 所以就自动转化为了kCGLineJoinBevel类型。
@property(nonatomic) CGFloat flatness;
确定弯曲路径短的绘制精度的因素。
@property(nonatomic) BOOL usesEvenOddFillRule; // Default is NO. When YES, the even-odd fill rule is used for drawing, clipping, and hit testing.
一个bool值指定even-odd规则是否在path可用。
- (void)setLineDash:(nullableconstCGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase;
设置线型 可设置成虚线。
注:pattern 线段数组 如:CGFloat dash[] = {1,1}; 代表实线和空白交替的长度 及先绘制1个长度再空1个,再绘制一个.....;
count数组长度 count值小于数组实际长度时,方法就会对相应长度的数组元素进行循环,而大于的时候 会有警告,没有效果;
phase 循环数组时跳过的长度,如pattern为{2,6},phase为1,则第一个元素画1的时候就跳过直接画6
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100,300)];
[bezierPath addLineToPoint:CGPointMake(150, 50)];
CGFloat patten[] = {4,6};
[bezierPath setLineDash:pattencount:2phase:1];
- (void)getLineDash:(nullableCGFloat *)pattern count:(nullableNSInteger *)count phase:(nullableCGFloat *)phase;
检索线型。
- (void)fill;
利用当前绘画属性填充路径封闭范围, 该方法在绘画之前会自动将开放子路径封闭, 填充部分不包含路径本身, 所以对于线宽较大的路径, 填充部分会跟部分路径重合。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100,300)];
[bezierPath addLineToPoint:CGPointMake(150, 50)];
[bezierPath addLineToPoint:CGPointMake(220, 80)];
bezierPath.lineWidth=5.0;
[bezierPath fill];
[bezierPath stroke];
- (void)stroke;
利用当前绘画属性沿着路径画线。
UIBezierPath*path = [UIBezierPathbezierPath];
// do something....
[path stroke];
- (void)fillWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
利用指定模式填充路径封闭范围, 该方法在绘画之前会自动将开放子路径封闭, 填充部分不包含路径本身, 所以对于线宽较大的路径, 填充部分会跟部分路径重合。
注意:CGBlendMode的值很多,大家有兴趣的可以自己挨个试试。
typedefCF_ENUM (int32_t, CGBlendMode) {
/* Available in Mac OS X 10.4 & later. */
kCGBlendModeNormal,
kCGBlendModeMultiply,
kCGBlendModeScreen,
kCGBlendModeOverlay,
kCGBlendModeDarken,
kCGBlendModeLighten,
kCGBlendModeColorDodge,
kCGBlendModeColorBurn,
kCGBlendModeSoftLight,
kCGBlendModeHardLight,
kCGBlendModeDifference,
kCGBlendModeExclusion,
kCGBlendModeHue,
kCGBlendModeSaturation,
kCGBlendModeColor,
kCGBlendModeLuminosity,
/* Available in Mac OS X 10.5 & later. R, S, and D are, respectively,
premultiplied result, source, and destination colors with alpha; Ra,
Sa, and Da are the alpha components of these colors.
The Porter-Duff "source over" mode is called `kCGBlendModeNormal':
R = S + D*(1 - Sa)
Note that the Porter-Duff "XOR" mode is only titularly related to the
classical bitmap XOR operation (which is unsupported by
CoreGraphics). */
kCGBlendModeClear, /* R = 0 */
kCGBlendModeCopy, /* R = S */
kCGBlendModeSourceIn, /* R = S*Da */
kCGBlendModeSourceOut, /* R = S*(1 - Da) */
kCGBlendModeSourceAtop, /* R = S*Da + D*(1 - Sa) */
kCGBlendModeDestinationOver, /* R = S*(1 - Da) + D */
kCGBlendModeDestinationIn, /* R = D*Sa */
kCGBlendModeDestinationOut, /* R = D*(1 - Sa) */
kCGBlendModeDestinationAtop, /* R = S*(1 - Da) + D*Sa */
kCGBlendModeXOR, /* R = S*(1 - Da) + D*(1 - Sa) */
kCGBlendModePlusDarker, /* R = MAX(0, (1 - D) + (1 - S)) */
kCGBlendModePlusLighter /* R = MIN(1, S + D) */
};
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100,300)];
[bezierPath addLineToPoint:CGPointMake(150, 50)];
[bezierPath addLineToPoint:CGPointMake(220, 80)];
bezierPath.lineWidth=5.0;
[bezierPath fillWithBlendMode:kCGBlendModeNormal alpha:0.4];
[bezierPath stroke];
- (void)strokeWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
利用指定模式沿着路径画线。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100,300)];
[bezierPath addLineToPoint:CGPointMake(150, 50)];
[bezierPath addLineToPoint:CGPointMake(220, 80)];
bezierPath.lineWidth=5.0;
[bezierPath strokeWithBlendMode:kCGBlendModeNormal alpha:0.4];
- (void)addClip;
剪切被接收者路径包围的区域该路径是带有剪切路径的当前绘图上下文。使得其成为我们当前的剪切路径。简单的说,就是一个path调用addClip之后,它所在的context的可见区域就变成了它的“fill area”,接下来的绘制,如果在这个区域外都会被无视。
//首先画一个三角形
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(100,300)];
[bezierPath addLineToPoint:CGPointMake(150, 50)];
[bezierPath addLineToPoint:CGPointMake(220, 80)];
bezierPath.lineWidth=5.0;
[bezierPath fillWithBlendMode:kCGBlendModeNormal alpha:0.4];
//然后调用addClip(裁剪)方法。
[bezierPath addClip];
//之后,在绘制一个圆弧。
[bezierPath addArcWithCenter:bezierPath.currentPoint radius:100 startAngle:M_PI_2 endAngle:2 * M_PI clockwise:YES];
[bezierPath stroke];
效果图上可以看出圆弧只显示了在三角形上的一部分。
- (void)setFill;
路径的填充颜色。
[[UIColor orangeColor] setFill];
- (void)setStroke;
路径的画线颜色。
[[UIColor orangeColor] setStroke];