UIBezierPath詳解

  • 此文源于網(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;
image

圖片來(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;
image

圖片來(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;
image

圖片來(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

image

/*

最大斜接長(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)顯示

*/

image

// 確定彎曲路徑短的繪制精度的因素

@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í)踐~敲出如下圖代碼

image
  • (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;

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末额各,一起剝皮案震驚了整個(gè)濱河市国觉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌虾啦,老刑警劉巖麻诀,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異傲醉,居然都是意外死亡针饥,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門需频,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人筷凤,你說(shuō)我怎么就攤上這事昭殉“撸” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵挪丢,是天一觀的道長(zhǎng)蹂风。 經(jīng)常有香客問(wèn)我,道長(zhǎng)乾蓬,這世上最難降的妖魔是什么惠啄? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮任内,結(jié)果婚禮上撵渡,老公的妹妹穿的比我還像新娘。我一直安慰自己死嗦,他們只是感情好趋距,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布瘾境。 她就那樣靜靜地躺著呆细,像睡著了一般。 火紅的嫁衣襯著肌膚如雪麸澜。 梳的紋絲不亂的頭發(fā)上摘盆,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天翼雀,我揣著相機(jī)與錄音,去河邊找鬼孩擂。 笑死狼渊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肋殴。 我是一名探鬼主播囤锉,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼护锤!你這毒婦竟也來(lái)了官地?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤烙懦,失蹤者是張志新(化名)和其女友劉穎驱入,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體氯析,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亏较,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了掩缓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雪情。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖你辣,靈堂內(nèi)的尸體忽然破棺而出巡通,到底是詐尸還是另有隱情尘执,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布宴凉,位于F島的核電站誊锭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏弥锄。R本人自食惡果不足惜丧靡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望籽暇。 院中可真熱鬧温治,春花似錦、人聲如沸图仓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)救崔。三九已至惶看,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間六孵,已是汗流浹背纬黎。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劫窒,地道東北人本今。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像主巍,于是被迫代替她去往敵國(guó)和親冠息。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • UIBezierPath詳解 我在寫本篇文章之前孕索,也沒有系統(tǒng)學(xué)習(xí)過(guò)貝塞爾曲線逛艰,只是曾經(jīng)某一次的需求需要使用到,才臨...
    白水灬煮一切閱讀 1,174評(píng)論 0 4
  • 使用UIBezierPath類可以創(chuàng)建基于矢量的路徑搞旭,這個(gè)類在UIKit中散怖。 此類是Core Graphics框架...
    XLsn0w閱讀 1,024評(píng)論 0 2
  • UIBezierPath用于定義一個(gè)直線/曲線組合而成的路徑,并且可以在自定義視圖中渲染該路徑肄渗。 注意:使用UIB...
    光之鹽汽水閱讀 17,765評(píng)論 2 29
  • 初始化方法解析 該方法將會(huì)創(chuàng)建一個(gè)閉合路徑, 起始點(diǎn)是 rect 參數(shù)的origin, 并且按照順時(shí)針方向添加直線...
    碼農(nóng)_會(huì)寫詩(shī)閱讀 299評(píng)論 0 0
  • 貝塞爾曲線(UIBezierPath)屬性镇眷、方法匯總 UIBezierPath主要用來(lái)繪制矢量圖形,它是基于Cor...
    AllureJM閱讀 467評(píng)論 0 0