說起這個貝塞爾曲線,其實可以實現(xiàn)很多功能的:曲線圖苍苞、折線圖固翰、進度條狼纬、畫板、不規(guī)則圖形等等骂际。下邊我們就來看看這條線疗琉。
使用UIBezierPath類可以創(chuàng)建基于矢量的路徑,這個類在UIKit中歉铝。此類是Core Graphics框架關于path的一個封裝盈简。使用此類可以定義簡單的形狀,如橢圓或者矩形太示,或者有多個直線和曲線段組成的形狀柠贤。
1.Bezier Path 基礎
UIBezierPath對象是CGPathRef數(shù)據(jù)類型的封裝。path如果是基于矢量形狀的类缤,都用直線和曲線段去創(chuàng)建臼勉。我們使用直線段去創(chuàng)建矩形和多邊形,使用曲線段去創(chuàng)建徊腿酢(arc)宴霸,圓或者其他復雜的曲線形狀。每一段都包括一個或者多個點膏蚓,繪圖命令定義如何去詮釋這些點瓢谢。每一個直線段或者曲線段的結束的地方是下一個的開始的地方。每一個連接的直線或者曲線段的集合成為subpath驮瞧。一個UIBezierPath對象定義一個完整的路徑包括一個或者多個subpaths氓扛。
創(chuàng)建和使用一個path對象的過程是分開的。創(chuàng)建path是第一步论笔,包含一下步驟:
(1)創(chuàng)建一個Bezierpath對象采郎。
(2)使用方法moveToPoint:去設置初始線段的起點。
(3)添加line或者curve去定義一個或者多個subpaths翅楼。
(4)改變UIBezierPath對象跟繪圖相關的屬性尉剩。
例如,我們可以設置stroked path的屬性lineWidth和lineJoinStyle毅臊。也可以設置filled path的屬性usesEvenOddFillRule理茎。
當創(chuàng)建path,我們應該管理path上面的點相對于原點(0管嬉,0)皂林,這樣我們在隨后就可以很容易的移動path了。為了繪制path對象蚯撩,我們要用到stroke和fill方法础倍。這些方法在current graphic context下渲染path的line和curve段。
2胎挎、使用UIBezierPath創(chuàng)建多邊形---在path下面添加直線條形成多邊形
多邊形是一些簡單的形狀,這些形狀是由一些直線線條組成沟启,我們可以用moveToPoint: 和 addLineToPoint:方法去構建忆家。
方法moveToPoint:設置我們想要創(chuàng)建形狀的起點。從這點開始德迹,我們可以用方法addLineToPoint:去創(chuàng)建一個形狀的線段芽卿。
我們可以連續(xù)的創(chuàng)建line,每一個line的起點都是先前的終點胳搞,終點就是指定的點卸例。
說明:closePath這個便利的方法使得我們不需要去畫最后一條線。
1肌毅、不規(guī)則多邊形筷转。
注意:這里的代碼是在一個繼承自UIView的- (void)drawRect:(CGRect)rect{}方法里面寫的。
如果我們講最后一句[aPath stroke];換成[aPath fill];我們會發(fā)現(xiàn)圖形被填充了:
這個stroke就是“(用筆等)畫”的意思悬而,可以理解為邊框呜舒,fill就是“填滿”得意思。
2笨奠、畫矩形阴绢。
一般我們的矩形不會需要貝塞爾就可以自己畫的,但是這個倒角矩形還是可以用的艰躺,看看這兩個矩形有什么區(qū)別就知道了。
我們點擊進這個枚舉類型可以看到
左上角倒角眨八、右上角倒角腺兴、左下角倒角、右下角倒角廉侧、全部倒角页响。這里我有兩個問題:
1、如果要求左上角和右上角同時倒角段誊,而下邊的兩個角不倒角闰蚕,怎么做?
2连舍、全部倒角没陡,倒角是正方形邊長的一半的時候就可以畫圓圈或者圓餅了。
因為我們可以看到上述是枚舉值索赏,盼玄,,哎潜腻,既然是枚舉值埃儿,那么我們就能解決第一個問題了:
這里我們可以討論一下倒角成圓的話題:一般我們倒角成圓慣用的是下邊的方法:
xxx.layer.cornerRadius=10;
xxx.layer.masksToBounds=YES;
關于這種方法我們之前在《TableView 優(yōu)化》的文章里面講到過:如果頁面上有很多個倒角融涣,上述方法操作童番,會是GPU負載迅速上升精钮,而解決方案是設置為:xxx.layer.shouldRasterize=YES;這樣可以把負載轉移給CPU,使得GPU和CPU比較平衡剃斧,進而使得tableview得到優(yōu)化轨香。(如果頁面上只有一兩個倒角的話,應該影響不大)
而我們這里貝塞爾實現(xiàn)畫圓的方法要比上述方法效率高悯衬,但是需要一些封裝弹沽。
3、畫弧線筋粗。
貝塞爾曲線策橘,那么貝塞爾肯定能畫弧線,畫弧線需要注意的還挺多娜亿,我們先實現(xiàn)效果丽已。如下圖:
首先我們看宏:有人將圓周率π寫成了3.1415926,當然這樣寫是可以的买决,但是我們保持嚴謹?shù)膽B(tài)度是將pi取xcode里面定義的沛婴,如下圖宏定義pi=M_PI。
然后我們點擊進去看看xcode自帶的pi的值督赤,精確到了小數(shù)點后邊35位嘁灯。(這玩意越精確自然是越好的,當然不影響大局)
然后我們再關注一下方法里面的這個參數(shù):clockwise躲舌,有道詞典翻譯一下我們可以知道這個詞是“順時針方向”丑婿,方法里面是BOOL值,看上邊的兩個圖片我們分別將BOOL值設置成了NO和YES没卸,NO就是“不是順時針方向”=逆時針方向羹奉,YES自然就是順時針方向了。我們可以看到這兩張圖上邊的弧線可以湊成一個圓约计。
另外我們可以看到我們的135度是沒有變化的诀拭,那么順時針135度就真的是135度的弧線,但是逆時針135度就是360-135=225度煤蚌。
再就是我們看一下弧線的起點耕挨,為啥是在那里,這就要說起xy軸的問題了
起點是在X軸的正方向上邊铺然。
下邊這個圖告訴我們0的位置在X軸的正方向上邊俗孝,同時這里也是一圈終止的地方,也就是2π魄健,圖中標明了是順時針方向赋铝,所以上圖我們的135°并且clockwise設置成YES的時候,是那個樣子的沽瘦。
那么關于弧線的起點我們就是要自己去算了革骨,就像下圖是的农尖,我的起點是在0度的基礎上加了90度,終點是180度良哲,順時針防線盛卡,那么就是這樣一個弧線。所以起點是自己可以計算的筑凫。
還有一個有趣的現(xiàn)象:我選擇fill滑沧,效果如下圖。(是不是想起了小學的時候求這個的面積:扇形的面積-一個三角形的面積巍实,哈哈)
我以為選擇fill后的效果是出來一個扇形呢滓技,結果不是。
4棚潦、畫曲線
貝塞爾曲線令漂,既然叫這個名字,那么就應該對得起哈哈丸边,自然可以畫曲線的叠必!
首先繪制二次貝塞爾曲線。我是這么理解這個二次貝塞爾曲線的:只有一個彎兒妹窖。
我們知道兩點確定一條直線纬朝,也可以這么說:兩點之間直線最短。那么這個二次貝塞爾曲線我們就可以理解為是把一條直線朝著一個方向拉彎了骄呼,不管你往上還是往下拉玄组,總之只朝著一個方向拉,那么這就是二次貝塞爾曲線谒麦。
實際上按照這個貝塞爾曲線畫二次貝塞爾曲線的方法:- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint中我們可以看到第一個參數(shù)是endPoint,也就是一開始我們有一個起點哆致,這個endPoint是終點绕德,這就是兩個點。第二個參數(shù)是controlPoint摊阀,字面上的意思我們就能知道:控制點耻蛇。這就是控制二次貝塞爾曲線拉彎程度的那個點。即下圖所示胞此。
通過改變這個controlPoint點臣咖,我們可以得到不同形狀的曲線。
然后我們來看三次貝塞爾曲線漱牵。理解了二次的夺蛇,三次的我們也就能理解了,還是先來一條直線酣胀,然后這次是兩個方向拉這個直線刁赦,最好這兩個方向是相反的娶聘,這樣的話我們可以看得更清楚一些,當然我們也可以設置成相同方向的兩個拉力甚脉,就是不明顯而已丸升。
把stroke換成fill我們得到下邊的圖像:
5、進度條
下邊紅框的內容是重點:是貝塞爾曲線和CALayer產生聯(lián)系的重要步驟牺氨,另外這個進度條的代碼狡耻,可以優(yōu)化一下,比方我們需要的是一個完成百分比85%的進度條猴凹,那么我們的self.shapeLayer.strokeEnd夷狰,那么我們加一個動畫,在2秒內完成從0到85%的一個動畫精堕,這就是進度條孵淘。
這里需要注意的是如果按照這個代碼完成后,進度條只轉了一圈就不轉了歹篓,那么可以修改一下add的初始值瘫证,我的就是設置為0.1的時候,只轉了一圈庄撮,其實也是在轉背捌,因為我在timer的事件中打了斷點的,斷了洞斯,不知道是什么原因毡庆,改成0.05以后,就一直不停的轉了烙如。么抗。。
暫且先研究了這么多亚铁,也不過是照著例子做了做蝇刀,加了一些自己的理解,希望給大家?guī)韼椭?/p>
具體如何折線圖和曲線圖這個暫且沒有研究徘溢,如果有網(wǎng)友有相關好的demo吞琐,希望可以告訴我,在此先謝謝了然爆。
6站粟、餅狀圖
加入宏定義,這樣就可以隨意的設置圓的圓心和半徑了曾雕。
這是點擊方法奴烙,就是不知道為什么點擊兩次。。缸沃。
上邊的點擊事件修改為touchesBegan:點擊就是一次了恰起。
在.h中將宏定義替換掉,這樣就算外漏了趾牧,那么我們就可以在定義貝塞爾view的時候傳入检盼。
當然,相對應的宏定義還要進行替換成self. xxx 翘单。下圖舉例紅色部分的修改吨枉。
下圖1、進行圓心和半徑的傳值 ? ? 2哄芜、進行貝塞爾view的旋轉 ? ? ?3貌亭、對方形的貝塞爾view進行裁剪
動態(tài)效果圖:點擊區(qū)域進行打印:
說明:這個圓餅只適合這個角度的认臊,而且只能是三塊餅圃庭,如果是四塊餅或者五塊餅,需要重新計算里面的self.radius*1.732/2失晴、self.radius/2剧腻、self.radius+self.radius*1.732/2。還是太脆弱涂屁,不通用书在,后期會優(yōu)化,期望效果是只要傳入餅的塊數(shù)等參數(shù)拆又,直接就能出來想要的圓餅儒旬。后期優(yōu)化吧。
參考:
最后一個最厲害帖族,從數(shù)學的角度講解了貝塞爾曲線的生成栈源,最主要的是還有動畫,可以更好的理解貝塞爾曲線的前因后果竖般。
最后凉翻,哪里不對的地方可以給我留言,我會及時改進的捻激,謝謝大家。