UIBezierPath

基礎(chǔ)知識

使用UIBezierPath可以創(chuàng)建基于矢量的路徑拍棕,此類是Core Graphics框架關(guān)于路徑的封裝掏呼。使用此類可以定義簡單的形狀蟆融,如橢圓井佑、矩形或者有多個直線和曲線段組成的形狀等属铁。

UIBezierPath是CGPathRef數(shù)據(jù)類型的封裝。如果是基于矢量形狀的路徑躬翁,都用直線和曲線去創(chuàng)建红选。我們使用直線段去創(chuàng)建矩形和多邊形,使用曲線去創(chuàng)建圓荒妨怼(arc)喇肋、圓或者其他復(fù)雜的曲線形狀。
使用UIBezierPath

畫圖步驟:

創(chuàng)建一個UIBezierPath
對象
調(diào)用-moveToPoint:
設(shè)置初始線段的起點
添加線或者曲線去定義一個或者多個子路徑
改變UIBezierPath
對象跟繪圖相關(guān)的屬性迹辐。如蝶防,我們可以設(shè)置畫筆的屬性、填充樣式等

UIBezierPath創(chuàng)建方法介紹
我們先看看UIBezierPath
類提供了哪些創(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;

下面我們一個一個地介紹其用途印荔。

+ (instancetype)bezierPath;

這個使用比較多低葫,因為這個工廠方法創(chuàng)建的對象,我們可以根據(jù)我們的需要任意定制樣式仍律,可以畫任何我們想畫的圖形嘿悬。

+ (instancetype)bezierPathWithRect:(CGRect)rect;

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

+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;

這個工廠方法根據(jù)一個矩形畫內(nèi)切曲線水泉。通常用它來畫圓或者橢圓善涨。

+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect
                        cornerRadius:(CGFloat)cornerRadius;
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect
                    byRoundingCorners:(UIRectCorner)corners 
                          cornerRadii:(CGSize)cornerRadii;

第一個工廠方法是畫矩形窒盐,但是這個矩形是可以畫圓角的。第一個參數(shù)是矩形钢拧,第二個參數(shù)是圓角大小蟹漓。 第二個工廠方法功能是一樣的,但是可以指定某一個角畫成圓角源内。像這種我們就可以很容易地給UIView
擴(kuò)展添加圓角的方法了葡粒。

+ (instancetype)bezierPathWithArcCenter:(CGPoint)center 
                             radius:(CGFloat)radius 
                         startAngle:(CGFloat)startAngle 
                           endAngle:(CGFloat)endAngle 
                          clockwise:(BOOL)clockwise;

這個工廠方法用于畫弧,參數(shù)說明如下:
center: 弧線中心點的坐標(biāo)
radius: 弧線所在圓的半徑
startAngle: 弧線開始的角度值
endAngle: 弧線結(jié)束的角度值
clockwise: 是否順時針畫弧線
溫馨提示
我們下面的代碼都是在自定義的BezierPathView類中下面的方法中調(diào)用:

- (void)drawRect:(CGRect)rect

畫三角形
先看效果圖:


image

// 畫三角形
- (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)];

// 最后的閉合線是可以通過調(diào)用closePath方法來自動生成的膜钓,也可以調(diào)用-addLineToPoint:方法來添加
//  [path addLineToPoint:CGPointMake(20, 20)];

[path closePath];

// 設(shè)置線寬
path.lineWidth = 1.5;

// 設(shè)置填充顏色
UIColor *fillColor = [UIColor greenColor];
[fillColor set];
[path fill];

// 設(shè)置畫筆顏色
UIColor *strokeColor = [UIColor blueColor];
[strokeColor set];

// 根據(jù)我們設(shè)置的各個點連線
[path stroke];
}

我們設(shè)置畫筆顏色通過set
方法:

UIColor *strokeColor = [UIColor blueColor];
[strokeColor set];

如果我們需要設(shè)置填充顏色嗽交,比如這里設(shè)置為綠色,那么我們需要在設(shè)置畫筆顏色之前先設(shè)置填充顏色呻此,否則畫筆顏色就被填充顏色替代了。也就是說腔寡,如果要讓填充顏色與畫筆顏色不一樣焚鲜,那么我們的順序必須是先設(shè)置填充顏色再設(shè)置畫筆顏色。如下放前,這兩者順序不能改變忿磅。因為我們設(shè)置填充顏色也是跟設(shè)置畫筆顏色一樣調(diào)用UIColor的-set方法。

// 設(shè)置填充顏色
UIColor *fillColor = [UIColor greenColor];
[fillColor set];
[path fill];

// 設(shè)置畫筆顏色
UIColor *strokeColor = [UIColor blueColor];
[strokeColor set];

畫矩形
先看效果圖:


image

// 畫矩形
- (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è)置畫筆顏色
UIColor *strokeColor = [UIColor blueColor];
[strokeColor set];

// 根據(jù)我們設(shè)置的各個點連線
[path stroke];
 }
lineCapStyle

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

/* Line cap styles. */

typedef CF_ENUM(int32_t, CGLineCap) {
   kCGLineCapButt,  默認(rèn)的
   kCGLineCapRound, 輕微圓角
   kCGLineCapSquare 第三個正方形
};
lineJoinStyle

屬性是用來設(shè)置兩條線連結(jié)點的樣式葱她,其中也有三個選擇:

/* Line join styles. */

typedef CF_ENUM(int32_t, CGLineJoin) {
   kCGLineJoinMiter, 默認(rèn)的表示斜接
   kCGLineJoinRound, 圓滑銜接
   kCGLineJoinBevel 斜角連接
};

畫圓
我們可以使用+ bezierPathWithOvalInRect:
方法來畫圓,當(dāng)我們傳的rect
參數(shù)是一下正方形時似扔,畫出來的就是圓吨些。
先看效果圖:


image
- (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è)置畫筆顏色
UIColor *strokeColor = [UIColor blueColor];
[strokeColor set];

// 根據(jù)我們設(shè)置的各個點連線
[path stroke];
}

注意:要畫圓炒辉,我們需要傳的rect參數(shù)必須是正方形哦豪墅!
畫橢圓
先看效果圖:

image

前面我們已經(jīng)畫圓了,我們可以使用+ bezierPathWithOvalInRect:
方法來畫圓黔寇,當(dāng)我們傳的rect
參數(shù)是一下正方形時偶器,畫出來的就是圓。那么我們要是不傳正方形缝裤,那么繪制出來的就是橢圓了屏轰。

// 畫橢圓
- (void)drawOvalPath {
// 傳的是不是正方形,因此就可以繪制出橢圓圓了
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, self.frame.size.width - 80, self.frame.size.height - 40)];

// 設(shè)置填充顏色
UIColor *fillColor = [UIColor greenColor];
[fillColor set];
[path fill];

// 設(shè)置畫筆顏色
UIColor *strokeColor = [UIColor blueColor];
[strokeColor set];

// 根據(jù)我們設(shè)置的各個點連線
[path stroke];
}

畫帶圓角的矩形

+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect
                        cornerRadius:(CGFloat)cornerRadius;
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect
                    byRoundingCorners:(UIRectCorner)corners 
                          cornerRadii:(CGSize)cornerRadii;

第一個工廠方法是畫矩形憋飞,但是這個矩形是可以畫圓角的霎苗。第一個參數(shù)是矩形,第二個參數(shù)是圓角大小榛做。 第二個工廠方法功能是一樣的叨粘,但是可以指定某一個角畫成圓角猾编。像這種我們就可以很容易地給UIView
擴(kuò)展添加圓角的方法了。
四個都是圓角10:


image
- (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è)置畫筆顏色
UIColor *strokeColor = [UIColor blueColor];
[strokeColor set];

// 根據(jù)我們設(shè)置的各個點連線
[path stroke];
}

如果要畫只有一個角是圓角升敲,那么我們就修改創(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)];

其中第一個參數(shù)一樣是傳了個矩形答倡,第二個參數(shù)是指定在哪個方向畫圓角,第三個參數(shù)是一個CGSize
類型驴党,用來指定水平和垂直方向的半徑的大小瘪撇。看下效果圖:


image

畫弧
畫弧前港庄,我們需要了解其參考系倔既,如下圖(圖片來自網(wǎng)絡(luò)):


image
 #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];
}

效果圖如下:


image

我們要明確一點,畫弧參數(shù)startAngle和endAngle
使用的是弧度鹏氧,而不是角度渤涌,因此我們需要將常用的角度轉(zhuǎn)換成弧度。對于效果圖中把还,我們設(shè)置弧的中心為控件的中心实蓬,起點弧度為0,也就是正東方向吊履,而終點是135度角的位置安皱。如果設(shè)置的clockwise:YES
是逆時針方向繪制,如果設(shè)置為NO艇炎,效果如下:


image

這兩者正好是相反的酌伊。

畫二次貝塞爾曲線
先來學(xué)習(xí)一下關(guān)于控制點,如下圖(圖片來自網(wǎng)絡(luò)):


image

畫二次貝塞爾曲線缀踪,是通過調(diào)用此方法來實現(xiàn)的:

- (void)drawSecondBezierPath {
UIBezierPath *path = [UIBezierPath bezierPath];

// 首先設(shè)置一個起始點
[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];
}

畫二次貝塞爾曲線的步驟:
先設(shè)置一個起始點居砖,也就是通過-moveToPoint:
設(shè)置
調(diào)用-addQuadCurveToPoint:controlPoint:
方法設(shè)置終端點和控制點,以畫二次曲線

在效果圖中驴娃,拱橋左邊的起始點就是我們設(shè)置的起始點悯蝉,最右邊的終點,就是我們設(shè)置的終端點托慨,而我們設(shè)置的控制點為(width / 2, 0)對應(yīng)于紅色矩形中水平方向在正中央鼻由,而垂直方向在最頂部。
這個樣式看起來很像sin或者cos函數(shù)吧厚棵?這兩個只是特例而已蕉世,其實可以畫任意圖形,只是想不到婆硬,沒有做不到的狠轻。

畫三次貝塞爾曲線
貝塞爾曲線必定通過首尾兩個點,稱為端點彬犯;中間兩個點雖然未必要通過向楼,但卻起到牽制曲線形狀路徑的作用查吊,稱作控制點。關(guān)于三次貝塞爾曲線的控制器湖蜕,看下圖:

image

提示:其組成是起始端點+控制點1+控制點2+終止端點
如下方法就是畫三次貝塞爾曲線的關(guān)鍵方法逻卖,以三個點畫一段曲線,一般和-moveToPoint:
配合使用昭抒。

- (void)addCurveToPoint:(CGPoint)endPoint  controlPoint1:(CGPoint)controlPoint1  controlPoint2:(CGPoint)controlPoint2

看下效果圖:


image

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

- (void)drawThirdBezierPath {
UIBezierPath *path = [UIBezierPath bezierPath];

 // 設(shè)置起始端點
[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];

}

我們需要注意评也,這里確定的起始端點為(20,150),終止端點為(300, 150)灭返,基水平方向是一致的盗迟。控制點1的坐標(biāo)是(160熙含,0)罚缕,水平方向相當(dāng)于在中間附近,這個參數(shù)可以調(diào)整怎静∮实控制點2的坐標(biāo)是(160,250)消约,如果以兩個端點的連線為水平線肠鲫,那么就是250-150=100员帮,也就是在水平線下100或粮。這樣看起來就像一個sin
函數(shù)了。
如果感覺這篇文章對您有所幫助捞高,順手點個喜歡氯材,謝謝啦

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市硝岗,隨后出現(xiàn)的幾起案子氢哮,更是在濱河造成了極大的恐慌,老刑警劉巖型檀,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冗尤,死亡現(xiàn)場離奇詭異,居然都是意外死亡胀溺,警方通過查閱死者的電腦和手機(jī)裂七,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來仓坞,“玉大人背零,你說我怎么就攤上這事∥薨#” “怎么了徙瓶?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵毛雇,是天一觀的道長。 經(jīng)常有香客問我侦镇,道長灵疮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任虽缕,我火速辦了婚禮始藕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘氮趋。我一直安慰自己伍派,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布剩胁。 她就那樣靜靜地躺著诉植,像睡著了一般。 火紅的嫁衣襯著肌膚如雪昵观。 梳的紋絲不亂的頭發(fā)上晾腔,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機(jī)與錄音啊犬,去河邊找鬼灼擂。 笑死,一個胖子當(dāng)著我的面吹牛觉至,可吹牛的內(nèi)容都是我干的剔应。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼语御,長吁一口氣:“原來是場噩夢啊……” “哼峻贮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起应闯,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤纤控,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后碉纺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體船万,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年骨田,在試婚紗的時候發(fā)現(xiàn)自己被綠了耿导。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡盛撑,死狀恐怖碎节,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抵卫,我是刑警寧澤狮荔,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布胎撇,位于F島的核電站,受9級特大地震影響殖氏,放射性物質(zhì)發(fā)生泄漏晚树。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一雅采、第九天 我趴在偏房一處隱蔽的房頂上張望爵憎。 院中可真熱鬧,春花似錦婚瓜、人聲如沸宝鼓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愚铡。三九已至,卻和暖如春胡陪,著一層夾襖步出監(jiān)牢的瞬間沥寥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工柠座, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留邑雅,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓妈经,卻偏偏與公主長得像淮野,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子狂塘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

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