- 此文源于網(wǎng)絡(luò)
使用UIBezierPath類可以創(chuàng)建基于矢量的路徑,這個(gè)類在UIKit中。此類是Core Graphics框架關(guān)于path的一個(gè)封裝蜈缤。使用此類可以定義簡(jiǎn)單的形狀,如橢圓或者矩形,或者有多個(gè)直線和曲線段組成的形狀诺擅。
Bezier Path 基礎(chǔ)
UIBezierPath對(duì)象是CGPathRef數(shù)據(jù)類型的封裝。path如果是基于矢量形狀的啡直,都用直線和曲線段去創(chuàng)建烁涌。我們使用直線段去創(chuàng)建矩形和多邊形,使用曲線段去創(chuàng)建痪泼佟(arc)撮执,圓或者其他復(fù)雜的曲線形狀。每一段都包括一個(gè)或者多個(gè)點(diǎn)舷丹,繪圖命令定義如何去詮釋這些點(diǎn)抒钱。每一個(gè)直線段或者曲線段的結(jié)束的地方是下一個(gè)的開始的地方。每一個(gè)連接的直線或者曲線段的集合成為subpath颜凯。一個(gè)UIBezierPath對(duì)象定義一個(gè)完整的路徑包括一個(gè)或者多個(gè)subpaths谋币。
UIBezierPath類頭文件定義
// 根據(jù)一個(gè)Rect畫一個(gè)矩形曲線
- (instancetype)bezierPath;
/**
根據(jù)一個(gè)Rect畫一個(gè)橢圓曲線 Rect為正方形時(shí)畫的是一個(gè)圓
@param rect CGRect一個(gè)矩形
*/
- (instancetype)bezierPathWithRect:(CGRect)rect;
/**
根據(jù)一個(gè)Rect畫一個(gè)圓角矩形曲線 (Radius:圓角半徑) 當(dāng)Rect為正方形時(shí)且Radius等于邊長(zhǎng)一半時(shí)畫的是一個(gè)圓
@param rect CGRect一個(gè)矩形
*/
- (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
/**
根據(jù)一個(gè)Rect畫一個(gè)圓角矩形曲線 當(dāng)Rect為正方形時(shí)且Radius等于邊長(zhǎng)一半時(shí)畫的是一個(gè)圓
@param rect CGRect一個(gè)矩形
@param cornerRadius 圓角半徑
*/
- (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius;
typedef NS_OPTIONS(NSUInteger, UIRectCorner) {
UIRectCornerTopLeft = 1 << 0,
UIRectCornerTopRight = 1 << 1,
UIRectCornerBottomLeft = 1 << 2,
UIRectCornerBottomRight = 1 << 3,
UIRectCornerAllCorners = ~0UL
};
/**
根據(jù)一個(gè)Rect針對(duì)四角中的某個(gè)或多個(gè)角設(shè)置圓角
@param rect CGRect一個(gè)矩形
@param corners 允許指定矩形的部分角為圓角,而其余的角為直角症概,取值來(lái)自枚舉
@param cornerRadii 指定了圓角的半徑蕾额,這個(gè)參數(shù)的取值是 CGSize 類型,也就意味著這里需要給出的是橢圓的半徑彼城。
*/
- (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;
/**
以某個(gè)中心點(diǎn)畫弧線
@param center 指定了圓弧所在正圓的圓心點(diǎn)坐標(biāo)
@param radius 指定了圓弧所在正圓的半徑
@param startAngle 指定了起始弧度位置 注意: 起始與結(jié)束這里是弧度
@param endAngle 指定了結(jié)束弧度位置
@param clockwise 指定了繪制方向诅蝶,以時(shí)鐘方向?yàn)榕袛嗷鶞?zhǔn) 看下圖
*/
- (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
圖片來(lái)自網(wǎng)絡(luò)
/**
根據(jù)CGPath創(chuàng)建并返回一個(gè)新的UIBezierPath對(duì)象
@param CGPath CGPathRef
*/
- (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;
@property(nonatomic)CGPathRef CGPath;
- (CGPathRef)CGPathNS_RETURNS_INNER_POINTER CF_RETURNS_NOT_RETAINED;
/**
設(shè)置第一個(gè)起始點(diǎn)到接收器
@param point 起點(diǎn)坐標(biāo)
*/
- (void)moveToPoint:(CGPoint)point;
/**
附加一條直線到接收器的路徑
@param point 要到達(dá)的坐標(biāo)
*/
- (void)addLineToPoint:(CGPoint)point;
/**
該方法就是畫三次貝塞爾曲線的關(guān)鍵方法退个,以三個(gè)點(diǎn)畫一段曲線,一般和moveToPoint:配合使用调炬。其實(shí)端點(diǎn)為moveToPoint:設(shè)置语盈,終止端點(diǎn)位為endPoint;筐眷±枇遥控制點(diǎn)1的坐標(biāo)controlPoint1,這個(gè)參數(shù)可以調(diào)整匀谣≌掌澹控制點(diǎn)2的坐標(biāo)是controlPoint2。
@param endPoint 終點(diǎn)坐標(biāo)
@param controlPoint1 控制點(diǎn)1
@param controlPoint2 控制點(diǎn)2 看下圖
*/
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
圖片來(lái)自網(wǎng)絡(luò)
/**
畫二次貝塞爾曲線武翎,是通過(guò)調(diào)用此方法來(lái)實(shí)現(xiàn)的烈炭。一般和moveToPoint:配合使用。endPoint終端點(diǎn)宝恶,controlPoint控制點(diǎn)符隙,對(duì)于二次貝塞爾曲線,只有一個(gè)控制點(diǎn)
@param endPoint 終點(diǎn)坐標(biāo)
@param controlPoint 控制點(diǎn) 看下圖
*/
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
圖片來(lái)自網(wǎng)絡(luò)
/**
添加一個(gè)弧線與bezierPathWithArcCenter:radius:startAngle:endAngle:clockwise:區(qū)別是bezierPathWithArcCenter它是初始化一個(gè)弧線,addArcWithCenter是添加一個(gè)弧線,共同點(diǎn)就是參數(shù)都一樣
@param center 指定了圓弧所在正圓的圓心點(diǎn)坐標(biāo)
@param radius 指定了圓弧所在正圓的半徑
@param startAngle 指定了起始弧度位置
@param endAngle 指定了結(jié)束弧度位置
@param clockwise 指定了繪制方向垫毙,以時(shí)鐘方向?yàn)榕袛嗷鶞?zhǔn)
*/
- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise NS_AVAILABLE_IOS(4_0);
/**
- 閉合線使用這個(gè)方法起始點(diǎn)與終點(diǎn)將相連
*/
- (void)closePath;
/**
- 移除所有坐標(biāo)點(diǎn)
*/
- (void)removeAllPoints;
// Appending paths
// 添加一個(gè)paths UIBezierPath
- (void)appendPath:(UIBezierPath *)bezierPath;
// Modified paths
// 創(chuàng)建并返回一個(gè)與當(dāng)前路徑相反的新的貝塞爾路徑對(duì)象
- (UIBezierPath *)bezierPathByReversingPath NS_AVAILABLE_IOS(6_0);
// Transforming paths
// 用指定的仿射變換矩陣變換路徑的所有點(diǎn)
- (void)applyTransform:(CGAffineTransform)transform;
// Path info
// 該值指示路徑是否有任何有效的元素霹疫。
@property(readonly,getter=isEmpty)BOOL empty;
// 路徑包括的矩形
@property(nonatomic,readonly)CGRect bounds;
// 圖形路徑中的當(dāng)前點(diǎn)
@property(nonatomic,readonly)CGPoint currentPoint;
// 接收器是否包含指定的點(diǎn)
- (BOOL)containsPoint:(CGPoint)point;
// Drawing properties
// 線寬
@property(nonatomic)CGFloat lineWidth;
typedef CF_ENUM(int32_t, CGLineCap) {
kCGLineCapButt, 默認(rèn)的
kCGLineCapRound, 輕微圓角
kCGLineCapSquare 正方形
};
// 端點(diǎn)類型
@property(nonatomic)CGLineCap lineCapStyle;
typedef CF_ENUM(int32_t, CGLineJoin) {
kCGLineJoinMiter, 默認(rèn)的表示斜接
kCGLineJoinRound, 圓滑銜接
kCGLineJoinBevel 斜角連接
};
// 連接類型
@property(nonatomic)CGLineJoin lineJoinStyle;
// 最大斜接長(zhǎng)度 斜接長(zhǎng)度指的是在兩條線交匯處內(nèi)角和外角之間的距離
@property(nonatomic)CGFloat miterLimit;// Used when lineJoinStyle is kCGLineJoinMiter
/*
最大斜接長(zhǎng)度 斜接長(zhǎng)度指的是在兩條線交匯處內(nèi)角和外角之間的距離
只有l(wèi)ineJoin屬性為kCALineJoinMiter時(shí)miterLimit才有效
邊角的角度越小,斜接長(zhǎng)度就會(huì)越大综芥。
為了避免斜接長(zhǎng)度過(guò)長(zhǎng)丽蝎,我們可以使用 miterLimit屬性。
如果斜接長(zhǎng)度超過(guò) miterLimit的值膀藐,邊角會(huì)以 lineJoin的 "bevel"即kCALineJoinBevel類型來(lái)顯示
*/
// 確定彎曲路徑短的繪制精度的因素
@property(nonatomic)CGFloat flatness;
// 一個(gè)bool值指定even-odd規(guī)則是否在path可用
@property(nonatomic)BOOL usesEvenOddFillRule;// Default is NO. When YES, the even-odd fill rule is used for drawing, clipping, and hit testing.
// 設(shè)置線型 可設(shè)置成虛線
CGFloat pattern[] = {1,1};
- (void)setLineDash:(nullableconst CGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase;
// 檢索線型
- (void)getLineDash:(nullableCGFloat )pattern count:(nullableNSInteger)count phase:(nullableCGFloat *)phase;
// Path operations on the current graphics context 當(dāng)前圖形上下文中的路徑操作:
// 填充顏色
- (void)fill;
// 利用當(dāng)前繪圖屬性沿著接收器的路徑繪制
- (void)stroke;
// These methods do not affect the blend mode or alpha of the current graphics context
// 用指定的混合模式和透明度值來(lái)描繪受接收路徑所包圍的區(qū)域
- (void)fillWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
// 使用指定的混合模式和透明度值沿著接收器路徑屠阻。繪制一行
- (void)strokeWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
// 剪切被接收者路徑包圍的區(qū)域該路徑是帶有剪切路徑的當(dāng)前繪圖上下文。使得其成為我們當(dāng)前的剪切路徑
- (void)addClip;
實(shí)踐~敲出如下圖代碼
-
(void)drawRect:(CGRect)rect {
UIColor *brushColor = [UIColorwhiteColor];
// 根據(jù)一個(gè)Rect 畫一個(gè)矩形曲線
UIBezierPath *rectangular = [UIBezierPathbezierPathWithRect:CGRectMake(5,5, 30, 30)];
[PNRed set];
[rectangular fill];
[brushColor set];
[rectangular stroke];
// 根據(jù)一個(gè)Rect畫一個(gè)橢圓曲線 Rect為正方形時(shí)畫的是一個(gè)圓
UIBezierPath *oval = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(40,5, 50,30)];
[PNBlue set];
[oval fill];
[brushColor set];
[oval stroke];
// 根據(jù)一個(gè)Rect 畫一個(gè)圓角矩形曲線 (Radius:圓角半徑) 當(dāng)Rect為正方形時(shí)且Radius等于邊長(zhǎng)一半時(shí)畫的是一個(gè)圓
UIBezierPath *roundedRect = [UIBezierPathbezierPathWithRoundedRect:CGRectMake(95,5, 40,30) cornerRadius:5];
[PNStarYellow set];
[roundedRect fill];
[brushColor set];
[roundedRect stroke];
// 根據(jù)一個(gè)Rect針對(duì)四角中的某個(gè)或多個(gè)角設(shè)置圓角
UIBezierPath *roundedRect2 = [UIBezierPathbezierPathWithRoundedRect:CGRectMake(140,5, 40,30) byRoundingCorners:UIRectCornerTopLeft|UIRectCornerBottomRightcornerRadii:CGSizeMake(10,50)];
[PNFreshGreen set];
[roundedRect2 fill];
[brushColor set];
[roundedRect2 stroke];
// 以某個(gè)中心點(diǎn)畫弧線
UIBezierPath *arcPath = [UIBezierPathbezierPathWithArcCenter:CGPointMake(200,15) radius:20startAngle:0endAngle:degreesToRadian(90)clockwise:YES];
[brushColor set];
[arcPath stroke];
// 添加一個(gè)弧線
UIBezierPath *arcPath2 = [UIBezierPathbezierPath];
[arcPath2 moveToPoint:CGPointMake(230,30)];
[arcPath2 addArcWithCenter:CGPointMake(265,30) radius:25startAngle:degreesToRadian(180)endAngle:degreesToRadian(360)clockwise:YES];
// 添加一個(gè)UIBezierPath
[arcPath2 appendPath:[UIBezierPathbezierPathWithArcCenter:CGPointMake(265,30) radius:20startAngle:0endAngle:M_PI*2clockwise:YES]];
[PNStarYellow set];
[arcPath2 stroke];
// 根據(jù)CGPath創(chuàng)建并返回一個(gè)新的UIBezierPath對(duì)象
UIBezierPath *be = [selfbezierPathWithCGPath];
[PNRed set];
[be stroke];
// 三角形
UIBezierPath *triangle = [UIBezierPathbezierPath];
[triangle moveToPoint:CGPointMake(145,165)];
[triangle addLineToPoint:CGPointMake(155,185)];
[triangle addLineToPoint:CGPointMake(135,185)];
[PNStarYellow set];
[triangle fill];
// [triangle stroke];
[triangle closePath];
// 二次貝塞爾曲線
UIBezierPath *quadBe = [UIBezierPathbezierPath];
[quadBe moveToPoint:CGPointMake(30,150)];
[quadBe addQuadCurveToPoint:CGPointMake(130,150) controlPoint:CGPointMake(30,70)];
UIBezierPath *quadBe2 = [UIBezierPathbezierPath];
[quadBe2 moveToPoint:CGPointMake(160,150)];
[quadBe2 addQuadCurveToPoint:CGPointMake(260,150) controlPoint:CGPointMake(210,50)];
[quadBe2 appendPath:quadBe];
quadBe2.lineWidth = 1.5f;
quadBe2.lineCapStyle = kCGLineCapSquare;
quadBe2.lineJoinStyle = kCGLineJoinRound;
[brushColor set];
[quadBe2 stroke];
// 三次貝塞爾曲線
UIBezierPath *threePath = [UIBezierPathbezierPath];
[threePath moveToPoint:CGPointMake(30,250)];
[threePath addCurveToPoint:CGPointMake(260,230) controlPoint1:CGPointMake(120,180) controlPoint2:CGPointMake(150,260)];
threePath.lineWidth = 1.5f;
threePath.lineCapStyle = kCGLineCapSquare;
threePath.lineJoinStyle = kCGLineJoinRound;
[brushColor set];
[threePath stroke];
}
-
(UIBezierPath *)bezierPathWithCGPath {
UIBezierPath *framePath;
CGFloat arrowWidth = 14;
CGMutablePathRef path =CGPathCreateMutable();
CGRect rectangle =CGRectInset(CGRectMake(0,0, CGRectGetWidth(self.bounds),CGRectGetWidth(self.bounds)),3,3);
CGPoint p[3] = {
{CGRectGetMidX(self.bounds)-arrowWidth/2,CGRectGetWidth(self.bounds)-6},
{CGRectGetMidX(self.bounds)+arrowWidth/2,CGRectGetWidth(self.bounds)-6},
{CGRectGetMidX(self.bounds),CGRectGetHeight(self.bounds)-4}
};
CGPathAddRoundedRect(path, NULL, rectangle, 5, 5);
CGPathAddLines(path, NULL, p, 3);
CGPathCloseSubpath(path);
// 根據(jù)CGPath創(chuàng)建并返回一個(gè)新的UIBezierPath對(duì)象
framePath = [UIBezierPath bezierPathWithCGPath:path];
CGPathRelease(path);
return framePath;
}