UIBezierPath用于定義一個直線/曲線組合而成的路徑,并且可以在自定義視圖中渲染該路徑。
注意:使用UIBezierPath繪畫的代碼寫在自定義視圖的drawRect:方法中。
一、創(chuàng)建UIBezierPath.
+ (instancetype)bezierPath;
初始化一個UIBezierPath對象。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
+ (instancetype)bezierPathWithRect:(CGRect)rect;
以CGRect為范圍,創(chuàng)建一個矩形路徑。
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(100, 100, 200, 300)];
+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
以CGRect為范圍,創(chuàng)建一個圓/橢圓。
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寬、高的值大的為準(zhǔn),如果超過其鄰近最短邊的一半,則已最短邊一半為準(zhǔn)。(自己試出來的)
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:結(jié)束的弧度(角度);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;
根據(jù)CGPath創(chuàng)建一個新的UIBezierPath。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
UIBezierPath *newPath = [UIBezierPath bezierPathWithCGPath:bezierPath.CGPath];
二、路徑操作函數(shù)
- (void)moveToPoint:(CGPoint)point;
將當(dāng)前點移動到指定的位置。
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:結(jié)束的弧度(角度);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;
使用一條直線閉合路徑的起點和終點, 該方法同時也會更新當(dāng)前點到新直線的終點(即路徑的起點)(使一個路徑變成閉合回路)。
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)];
注:在效果圖中可以看出,在調(diào)用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);
返回一個翻轉(zhuǎn)已有路徑的新路徑。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
UIBezierPath*path2 = [bezierPath bezierPathByReversingPath];
- (void)applyTransform:(CGAffineTransform)transform;
對路徑中的所有點進(jìn)行二維形變, 該變化立即生效, 且為永久性改變所有點。
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;
可以封閉所有路徑點的最小矩形范圍, 包括多次貝塞爾曲線的控制點在內(nèi)。
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
CGRect bounds = bezierPath.bounds;
@property(nonatomic,readonly) CGPoint currentPoint;
路徑當(dāng)前所在點。
UIBezierPath*path = [UIBezierPathbezierPath];
CGPoint currentPoint = path.currentPoint;
- (BOOL)containsPoint:(CGPoint)point;
是否包含指定點。
UIBezierPath*path = [UIBezierPathbezierPath];
BOOL isContainsPoint = [path containsPoint:CGPointMake(20,30)];
四、繪圖相關(guān)方法和屬性
@property(nonatomic) CGFloat lineWidth;
路徑的線寬。
UIBezierPath*path = [UIBezierPath bezierPath];
path.lineWidth =10;
@property(nonatomic) CGLineCap lineCapStyle;
路徑的終點形狀, 該屬性適用于開放路徑的起點和終點。
注意:lineCapStyle的值:
typedefCF_ENUM(int32_t, CGLineCap) {
? ? kCGLineCapButt, ? ? ? ? ? ? ? ?//方形結(jié)束, 結(jié)束位置正好為精確位置?!J(rèn)值
? ? kCGLineCapRound, ? ? ? ? ? ?//圓形結(jié)束, 結(jié)束位置超過精確位置半個線寬。
? ? kCGLineCapSquare ? ? ? ? ? ?//方形結(jié)束, 結(jié)束位置超過精確位置半個線寬。
};
UIBezierPath*path = [UIBezierPath bezierPath];
path.lineCapStyle = kCGLineCapButt;
@property(nonatomic) CGLineJoin lineJoinStyle;
路徑的連接點(拐角)形狀。
注意:lineJoinStyle的值:
typedefCF_ENUM(int32_t, CGLineJoin) {
? ? kCGLineJoinMiter, ? ? ? ? ? ? ? ?//全部連接(尖角)?!J(rèn)值
? ? kCGLineJoinRound, ? ? ? ? ? ? ?//圓形連接。(圓角)
? ? kCGLineJoinBevel ? ? ? ? ? ? ? ?//斜角連接。(切角)
};

UIBezierPath*path = [UIBezierPath bezierPath];
path.lineJoinStyle = kCGLineJoinMiter;
@property(nonatomic) CGFloat miterLimit; // Used when lineJoinStyle is kCGLineJoinMiter
最大斜接長度,怎么理解呢?就是上圖中拐角處外面尖角和內(nèi)部尖角的距離。但是這個只有在kCGLineJoinMiter情況下使用才有效果,如果這個miterLimit小于斜接長度,就成為了kCGLineJoinBevel類型。
UIBezierPath*path = [UIBezierPath bezierPath];
path.lineJoinStyle = kCGLineJoinMiter;
path.miterLimit = 1; ? ? ? ? ? ? ? ?////這里設(shè)為1 因為斜接長度超過了1 所以就自動轉(zhuǎn)化為了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規(guī)則是否在path可用。
- (void)setLineDash:(nullableconstCGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase;
設(shè)置線型 可設(shè)置成虛線。
注:pattern 線段數(shù)組 如:CGFloat dash[] = {1,1}; 代表實線和空白交替的長度 及先繪制1個長度再空1個,再繪制一個.....;
????????count數(shù)組長度 count值小于數(shù)組實際長度時,方法就會對相應(yīng)長度的數(shù)組元素進(jìn)行循環(huán),而大于的時候 會有警告,沒有效果; ? ? ? ? ? ? ? ? ? ? ? ? ??
????????phase 循環(huán)數(shù)組時跳過的長度,如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;
利用當(dāng)前繪畫屬性填充路徑封閉范圍, 該方法在繪畫之前會自動將開放子路徑封閉, 填充部分不包含路徑本身, 所以對于線寬較大的路徑, 填充部分會跟部分路徑重合。
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;
利用當(dāng)前繪畫屬性沿著路徑畫線。
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;
剪切被接收者路徑包圍的區(qū)域該路徑是帶有剪切路徑的當(dāng)前繪圖上下文。使得其成為我們當(dāng)前的剪切路徑。簡單的說,就是一個path調(diào)用addClip之后,它所在的context的可見區(qū)域就變成了它的“fill area”,接下來的繪制,如果在這個區(qū)域外都會被無視。
//首先畫一個三角形
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];
//然后調(diào)用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];