UIBezierPath詳解

UIBezierPath詳解

我在寫(xiě)本篇文章之前,也沒(méi)有系統(tǒng)學(xué)習(xí)過(guò)貝塞爾曲線,只是曾經(jīng)某一次的需求需要使用到,才臨時(shí)百度看了一看而且使用最基本的功能?,F(xiàn)在總算有時(shí)間停下來(lái)好好研究研究這個(gè)神奇而偉大的貝塞爾先生!

基礎(chǔ)知識(shí)

使用UIBezierPath可以創(chuàng)建基于矢量的路徑,此類(lèi)是Core Graphics框架關(guān)于路徑的封裝。使用此類(lèi)可以定義簡(jiǎn)單的形狀,如橢圓、矩形或者有多個(gè)直線和曲線段組成的形狀等。

UIBezierPath是CGPathRef數(shù)據(jù)類(lèi)型的封裝。如果是基于矢量形狀的路徑,都用直線和曲線去創(chuàng)建。我們使用直線段去創(chuàng)建矩形和多邊形,使用曲線去創(chuàng)建圓?。╝rc)、圓或者其他復(fù)雜的曲線形狀。

使用UIBezierPath畫(huà)圖步驟:

創(chuàng)建一個(gè)UIBezierPath對(duì)象

調(diào)用-moveToPoint:設(shè)置初始線段的起點(diǎn)

添加線或者曲線去定義一個(gè)或者多個(gè)子路徑

改變UIBezierPath對(duì)象跟繪圖相關(guān)的屬性。如,我們可以設(shè)置畫(huà)筆的屬性、填充樣式等

UIBezierPath創(chuàng)建方法介紹

我們先看看UIBezierPath類(lèi)提供了哪些創(chuàng)建方式,這些都是工廠方法,直接使用即可。

+ (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;

下面我們一個(gè)一個(gè)地介紹其用途。

+ (instancetype)bezierPath;

這個(gè)使用比較多,因?yàn)檫@個(gè)工廠方法創(chuàng)建的對(duì)象,我們可以根據(jù)我們的需要任意定制樣式,可以畫(huà)任何我們想畫(huà)的圖形。

+ (instancetype)bezierPathWithRect:(CGRect)rect;

這個(gè)工廠方法根據(jù)一個(gè)矩形畫(huà)貝塞爾曲線。

+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;

這個(gè)工廠方法根據(jù)一個(gè)矩形畫(huà)內(nèi)切曲線。通常用它來(lái)畫(huà)圓或者橢圓。

+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect

cornerRadius:(CGFloat)cornerRadius;

+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect

byRoundingCorners:(UIRectCorner)corners

cornerRadii:(CGSize)cornerRadii;

第一個(gè)工廠方法是畫(huà)矩形,但是這個(gè)矩形是可以畫(huà)圓角的。第一個(gè)參數(shù)是矩形,第二個(gè)參數(shù)是圓角大小。

第二個(gè)工廠方法功能是一樣的,但是可以指定某一個(gè)角畫(huà)成圓角。像這種我們就可以很容易地給UIView擴(kuò)展添加圓角的方法了。

+ (instancetype)bezierPathWithArcCenter:(CGPoint)center

radius:(CGFloat)radius

startAngle:(CGFloat)startAngle

endAngle:(CGFloat)endAngle

clockwise:(BOOL)clockwise;

這個(gè)工廠方法用于畫(huà)弧,參數(shù)說(shuō)明如下:

center: 弧線中心點(diǎn)的坐標(biāo)

radius: 弧線所在圓的半徑

startAngle: 弧線開(kāi)始的角度值

endAngle: 弧線結(jié)束的角度值

clockwise: 是否順時(shí)針畫(huà)弧線

溫馨提示:我們下面的代碼都是在自定義的BezierPathView類(lèi)中的- (void)drawRect:(CGRect)rect方法中調(diào)用

畫(huà)三角形

先看效果圖:

// 畫(huà)三角形

- (void)drawTrianglePath {

UIBezierPath *path = [UIBezierPath bezierPath];

[path moveToPoint:CGPointMake(20, 20)];

[path addLineToPoint:CGPointMake(self.frame.size.width - 40, 20)];

[path addLineToPoint:CGPointMake(self.frame.size.width / 2, self.frame.size.height - 20)];

// 最后的閉合線是可以通過(guò)調(diào)用closePath方法來(lái)自動(dòng)生成的,也可以調(diào)用-addLineToPoint:方法來(lái)添加

//? [path addLineToPoint:CGPointMake(20, 20)];

[path closePath];

// 設(shè)置線寬

path.lineWidth = 1.5;

// 設(shè)置填充顏色

UIColor *fillColor = [UIColor greenColor];

[fillColor set];

[path fill];

// 設(shè)置畫(huà)筆顏色

UIColor *strokeColor = [UIColor blueColor];

[strokeColor set];

// 根據(jù)我們?cè)O(shè)置的各個(gè)點(diǎn)連線

[path stroke];

}

我們?cè)O(shè)置畫(huà)筆顏色通過(guò)set方法:

UIColor *strokeColor = [UIColor blueColor];

[strokeColor set];

如果我們需要設(shè)置填充顏色,比如這里設(shè)置為綠色,那么我們需要在設(shè)置畫(huà)筆顏色之前先設(shè)置填充顏色,否則畫(huà)筆顏色就被填充顏色替代了。也就是說(shuō),如果要讓填充顏色與畫(huà)筆顏色不一樣,那么我們的順序必須是先設(shè)置填充顏色再設(shè)置畫(huà)筆顏色。如下,這兩者順序不能改變。因?yàn)槲覀冊(cè)O(shè)置填充顏色也是跟設(shè)置畫(huà)筆顏色一樣調(diào)用UIColor的-set方法。

// 設(shè)置填充顏色

UIColor *fillColor = [UIColor greenColor];

[fillColor set];

[path fill];

// 設(shè)置畫(huà)筆顏色

UIColor *strokeColor = [UIColor blueColor];

[strokeColor set];

畫(huà)矩形

先看效果圖:

// 畫(huà)矩形

- (void)drawRectPath {

UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40)];

path.lineWidth = 1.5;

path.lineCapStyle = kCGLineCapRound;

path.lineJoinStyle = kCGLineJoinBevel;

// 設(shè)置填充顏色

UIColor *fillColor = [UIColor greenColor];

[fillColor set];

[path fill];

// 設(shè)置畫(huà)筆顏色

UIColor *strokeColor = [UIColor blueColor];

[strokeColor set];

// 根據(jù)我們?cè)O(shè)置的各個(gè)點(diǎn)連線

[path stroke];

}

lineCapStyle屬性是用來(lái)設(shè)置線條拐角帽的樣式的,其中有三個(gè)選擇:

/* Line cap styles. */

typedef CF_ENUM(int32_t, CGLineCap) {

kCGLineCapButt,

kCGLineCapRound,

kCGLineCapSquare

};

其中,第一個(gè)是默認(rèn)的,第二個(gè)是輕微圓角,第三個(gè)正方形。

lineJoinStyle屬性是用來(lái)設(shè)置兩條線連結(jié)點(diǎn)的樣式,其中也有三個(gè)選擇:

/* Line join styles. */

typedef CF_ENUM(int32_t, CGLineJoin) {

kCGLineJoinMiter,

kCGLineJoinRound,

kCGLineJoinBevel

};

其中,第一個(gè)是默認(rèn)的表示斜接,第二個(gè)是圓滑銜接,第三個(gè)是斜角連接。

畫(huà)圓

我們可以使用+ bezierPathWithOvalInRect:方法來(lái)畫(huà)圓,當(dāng)我們傳的rect參數(shù)是一下正方形時(shí),畫(huà)出來(lái)的就是圓。

先看效果圖:

- (void)drawCiclePath {

// 傳的是正方形,因此就可以繪制出圓了

UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.width - 40)];

// 設(shè)置填充顏色

UIColor *fillColor = [UIColor greenColor];

[fillColor set];

[path fill];

// 設(shè)置畫(huà)筆顏色

UIColor *strokeColor = [UIColor blueColor];

[strokeColor set];

// 根據(jù)我們?cè)O(shè)置的各個(gè)點(diǎn)連線

[path stroke];

}

注意:要畫(huà)圓,我們需要傳的rect參數(shù)必須是正方形哦!

畫(huà)橢圓

先看效果圖:

前面我們已經(jīng)畫(huà)圓了,我們可以使用+ bezierPathWithOvalInRect:方法來(lái)畫(huà)圓,當(dāng)我們傳的rect參數(shù)是一下正方形時(shí),畫(huà)出來(lái)的就是圓。那么我們要是不傳正方形,那么繪制出來(lái)的就是橢圓了。

// 畫(huà)橢圓

- (void)drawOvalPath {

// 傳的是不是正方形,因此就可以繪制出橢圓圓了

UIBezierPathpath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, self.frame.size.width - 80, self.frame.size.height - 40)];

// 設(shè)置填充顏色

UIColorfillColor = [UIColor greenColor];

[fillColor set];

[path fill];

// 設(shè)置畫(huà)筆顏色

UIColorstrokeColor = [UIColor blueColor];

[strokeColor set];

// 根據(jù)我們?cè)O(shè)置的各個(gè)點(diǎn)連線

[path stroke];

}

##### 畫(huà)帶圓角的矩形

**

+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect

cornerRadius:(CGFloat)cornerRadius;

+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect

byRoundingCorners:(UIRectCorner)corners

cornerRadii:(CGSize)cornerRadii;

第一個(gè)工廠方法是畫(huà)矩形,但是這個(gè)矩形是可以畫(huà)圓角的。第一個(gè)參數(shù)是矩形,第二個(gè)參數(shù)是圓角大小。

第二個(gè)工廠方法功能是一樣的,但是可以指定某一個(gè)角畫(huà)成圓角。像這種我們就可以很容易地給UIView擴(kuò)展添加圓角的方法了。

四個(gè)都是圓角10:

- (void)drawRoundedRectPath {

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40) cornerRadius:10];

// 設(shè)置填充顏色

UIColor *fillColor = [UIColor greenColor];

[fillColor set];

[path fill];

// 設(shè)置畫(huà)筆顏色

UIColor *strokeColor = [UIColor blueColor];

[strokeColor set];

// 根據(jù)我們?cè)O(shè)置的各個(gè)點(diǎn)連線

[path stroke];

}

如果要畫(huà)只有一個(gè)角是圓角,那么我們就修改創(chuàng)建方法:

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40) byRoundingCorners:UIRectCornerTopRight cornerRadii:CGSizeMake(20, 20)];

其中第一個(gè)參數(shù)一樣是傳了個(gè)矩形,第二個(gè)參數(shù)是指定在哪個(gè)方向畫(huà)圓角,第三個(gè)參數(shù)是一個(gè)CGSize類(lèi)型,用來(lái)指定水平和垂直方向的半徑的大小??聪滦Ч麍D:

畫(huà)弧

畫(huà)弧前,我們需要了解其參考系,如下圖(圖片來(lái)自網(wǎng)絡(luò)):

#define? kDegreesToRadians(degrees)? ((pi * degrees)/ 180)

- (void)drawARCPath {

const CGFloat pi = 3.14159265359;

CGPoint center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);

UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center

radius:100

startAngle:0

endAngle:kDegreesToRadians(135)

clockwise:YES];

path.lineCapStyle = kCGLineCapRound;

path.lineJoinStyle = kCGLineJoinRound;

path.lineWidth = 5.0;

UIColor *strokeColor = [UIColor redColor];

[strokeColor set];

[path stroke];

}

效果圖如下:

我們要明確一點(diǎn),畫(huà)弧參數(shù)startAngle和endAngle使用的是弧度,而不是角度,因此我們需要將常用的角度轉(zhuǎn)換成弧度。對(duì)于效果圖中,我們?cè)O(shè)置弧的中心為控件的中心,起點(diǎn)弧度為0,也就是正東方向,而終點(diǎn)是135度角的位置。如果設(shè)置的clockwise:YES是逆時(shí)針?lè)较蚶L制,如果設(shè)置為NO,效果如下:

這兩者正好是相反的。

畫(huà)二次貝塞爾曲線

先來(lái)學(xué)習(xí)一下關(guān)于控制點(diǎn),如下圖(圖片來(lái)自網(wǎng)絡(luò)):

畫(huà)二次貝塞爾曲線,是通過(guò)調(diào)用此方法來(lái)實(shí)現(xiàn)的:

- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint

參數(shù)說(shuō)明:

endPoint:終端點(diǎn)

controlPoint:控制點(diǎn),對(duì)于二次貝塞爾曲線,只有一個(gè)控制點(diǎn)

看效果圖:

- (void)drawSecondBezierPath {

UIBezierPath *path = [UIBezierPath bezierPath];

// 首先設(shè)置一個(gè)起始點(diǎn)

[path moveToPoint:CGPointMake(20, self.frame.size.height - 100)];

// 添加二次曲線

[path addQuadCurveToPoint:CGPointMake(self.frame.size.width - 20, self.frame.size.height - 100)

controlPoint:CGPointMake(self.frame.size.width / 2, 0)];

path.lineCapStyle = kCGLineCapRound;

path.lineJoinStyle = kCGLineJoinRound;

path.lineWidth = 5.0;

UIColor *strokeColor = [UIColor redColor];

[strokeColor set];

[path stroke];

}

畫(huà)二次貝塞爾曲線的步驟:

先設(shè)置一個(gè)起始點(diǎn),也就是通過(guò)-moveToPoint:設(shè)置

調(diào)用-addQuadCurveToPoint:controlPoint:方法設(shè)置終端點(diǎn)和控制點(diǎn),以畫(huà)二次曲線

在效果圖中,拱橋左邊的起始點(diǎn)就是我們?cè)O(shè)置的起始點(diǎn),最右邊的終點(diǎn),就是我們?cè)O(shè)置的終端點(diǎn),而我們?cè)O(shè)置的控制點(diǎn)為(width / 2, 0)對(duì)應(yīng)于紅色矩形中水平方向在正中央,而垂直方向在最頂部。

這個(gè)樣式看起來(lái)很像sin或者cos函數(shù)吧?這兩個(gè)只是特例而已,其實(shí)可以畫(huà)任意圖形,只是想不到,沒(méi)有做不到的。

畫(huà)三次貝塞爾曲線

貝塞爾曲線必定通過(guò)首尾兩個(gè)點(diǎn),稱(chēng)為端點(diǎn);中間兩個(gè)點(diǎn)雖然未必要通過(guò),但卻起到牽制曲線形狀路徑的作用,稱(chēng)作控制點(diǎn)。關(guān)于三次貝塞爾曲線的控制器,看下圖:

提示:其組成是起始端點(diǎn)+控制點(diǎn)1+控制點(diǎn)2+終止端點(diǎn)

如下方法就是畫(huà)三次貝塞爾曲線的關(guān)鍵方法,以三個(gè)點(diǎn)畫(huà)一段曲線,一般和-moveToPoint:配合使用。

- (void)addCurveToPoint:(CGPoint)endPoint

controlPoint1:(CGPoint)controlPoint1

controlPoint2:(CGPoint)controlPoint2

看下效果圖:

實(shí)現(xiàn)代碼是這樣的:

- (void)drawThirdBezierPath {

UIBezierPath *path = [UIBezierPath bezierPath];

// 設(shè)置起始端點(diǎn)

[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];

}

我們需要注意,這里確定的起始端點(diǎn)為(20,150),終止端點(diǎn)為(300, 150),基水平方向是一致的??刂泣c(diǎn)1的坐標(biāo)是(160,0),水平方向相當(dāng)于在中間附近,這個(gè)參數(shù)可以調(diào)整??刂泣c(diǎn)2的坐標(biāo)是(160,250),如果以兩個(gè)端點(diǎn)的連線為水平線,那么就是250-150=100,也就是在水平線下100。這樣看起來(lái)就像一個(gè)sin函數(shù)了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 基礎(chǔ)知識(shí) 使用UIBezierPath可以創(chuàng)建基于矢量的路徑,此類(lèi)是Core Graphics框架關(guān)于路徑的封裝。...
    十里桃花不及你閱讀 972評(píng)論 0 5
  • 1.使用UIBezierPath畫(huà)圖步驟 創(chuàng)建一個(gè)UIBezierPath對(duì)象 調(diào)用-moveToPoint:設(shè)置...
    翹楚iOS9閱讀 770評(píng)論 1 2
  • Quartz2D以及drawRect的重繪機(jī)制字?jǐn)?shù)1487 閱讀21 評(píng)論1 喜歡1一、什么是Quartz2D Q...
    PurpleWind閱讀 926評(píng)論 0 3
  • 你脖子揚(yáng)起來(lái)看云云就散了看雨雨就收了看我我就酥了 你是天地生的美得超越人形世間有兩種罪惡你笑是一種你不笑是另外一種
    Terrence_zxd閱讀 340評(píng)論 0 2
  • 清冷的夜 覓溫暖的光 心去向何方 不經(jīng)意 見(jiàn)那一回眸的清池 竟點(diǎn)了久違的心事 久久看著 那張老照片發(fā)呆 緩緩念向 ...
    老兵李閱讀 173評(píng)論 0 0

友情鏈接更多精彩內(nèi)容