Android自定義View進階 - 貝塞爾曲線
Path之貝塞爾曲線
作者微博: @GcsSloop
【本系列相關文章】
在上一篇文章Path之基本圖形中我們瞭解了Path的基本使用方法,本次瞭解Path中非常非常非常重要的內容-貝塞爾曲線。
一.Path常用方法表
為了相容性(偷懶) 本表格中去除了在API21(即安卓版本5.0)以上才新增的方法。忍不住吐槽一下,為啥看起來有些順手就能寫的過載方法要等到API21才新增上啊。寶寶此刻內心也是崩潰的。
作用 | 相關方法 | 備註 |
---|---|---|
移動起點 | moveTo | 移動下一次操作的起點位置 |
設定終點 | setLastPoint | 重置當前path中最後一個點位置,如果在繪製之前呼叫,效果和moveTo相同 |
連線直線 | lineTo | 新增上一個點到當前點之間的直線到Path |
閉合路徑 | close | 連線第一個點連線到最後一個點,形成一個閉合區域 |
新增內容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 新增(矩形, 圓角矩形, 橢圓, 圓, 路徑, 圓弧) 到當前Path (注意addArc和arcTo的區別) |
是否為空 | isEmpty | 判斷Path是否為空 |
是否為矩形 | isRect | 判斷path是否是一個矩形 |
替換路徑 | set | 用新的路徑替換到當前路徑所有內容 |
偏移路徑 | offset | 對當前路徑之前的操作進行偏移(不會影響之後的操作) |
貝塞爾曲線 | quadTo, cubicTo | 分別為二次和三次貝塞爾曲線的方法 |
rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | 不帶r的方法是基於原點的座標系(偏移量),rXxx方法是基於當前點座標系(偏移量) |
填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 設定,獲取,判斷和切換填充模式 |
提示方法 | incReserve | 提示Path還有多少個點等待加入(這個方法貌似會讓Path優化儲存結構) |
布林操作(API19) | op | 對兩個Path進行布林運算(即取交集、並集等操作) |
計算邊界 | computeBounds | 計算Path的邊界 |
重置路徑 | reset, rewind | 清除Path中的內容(reset相當於重置到new Path階段,rewind會保留Path的資料結構) |
矩陣操作 | transform | 矩陣變換 |
二.Path詳解
上一次除了一些常用函式之外,講解的基本上都是直線,本次需要了解其中的曲線部分,說到曲線,就不得不提大名鼎鼎的貝塞爾曲線。它的發明者是下面這個人(法國數學家PierreBézier)。
貝塞爾曲線能幹什麼?
貝塞爾曲線的運用是十分廣泛的,可以說貝塞爾曲線奠定了計算機繪圖的基礎(因為它可以將任何複雜的圖形用精確的數學語言進行描述),在你不經意間就已經使用過它了。
你會使用Photoshop的話,你可能會注意到裡面有一個鋼筆工具,這個鋼筆工具核心就是貝塞爾曲線。
你說你不會PS? 沒關係,你如果看過前面的文章或者用過2D繪圖,肯定繪製過圓,圓弧,圓角矩形等這些東西。這裡面的圓弧部分全部都是貝塞爾曲線的運用。
貝塞爾曲線作用十分廣泛,簡單舉幾個的栗子:
- QQ小紅點拖拽效果
- 一些炫酷的下拉重新整理控制元件
- 閱讀軟體的翻書效果
- 一些平滑的折線圖的製作
- 很多炫酷的動畫效果
如何輕鬆入門貝塞爾曲線?
雖然貝塞爾曲線用途非常廣泛,然而目前貌似並沒有適合的中文教程,能夠搜尋出來Android關於貝塞爾曲線的中文文章基本可以分為以下幾種:
* 科普型(只是讓人瞭解貝塞爾,並沒有實質性的內容)
* 裝逼型(擺出來一大堆公式,引用一堆英文原文)
* 基礎型(僅僅是講解貝塞爾曲線的兩個函式用法)
* 實戰型(根據例項講解其中貝塞爾曲線的運用)
以上幾種型別中比較有用的就是基礎型和實戰型,但兩者各有不足,本文會綜合兩者內容,從零開始學習貝塞爾曲線。
第一步.理解貝塞爾曲線的原理
此處理解貝塞爾曲線並非是學會公式的推倒過程,而是要了解貝塞爾曲線是如何生成的。貝塞爾曲線是用一系列點來控制曲線狀態的,我將這些點簡單分為兩類:
型別 | 作用 |
---|---|
資料點 | 確定曲線的起始和結束位置 |
控制點 | 確定曲線的彎曲程度 |
此處暫時僅作了解概念,接下來就會講解其中詳細的含義。
一階曲線原理:
一階曲線是沒有控制點的,僅有兩個資料點(A 和 B),最終效果一個線段。
上圖表示的是一階曲線生成過程中的某一個階段,動態過程可以參照下圖。
PS:一階曲線其實就是前面講解過的lineTo。
二階曲線原理:
二階曲線由兩個資料點(A 和 C),一個控制點(B)來描述曲線狀態,大致如下:
上圖中紅色曲線部分就是傳說中的二階貝塞爾曲線,那麼這條紅色曲線是如何生成的呢?接下來我們就以其中的一個狀態分析一下:
連線AB BC,並在AB上取點D,BC上取點E,使其滿足條件:
連線DE,取點F,使得:
這樣獲取到的點F就是貝塞爾曲線上的一個點,動態過程如下:
PS: 二階曲線對應的方法是quadTo
三階曲線原理:
三階曲線由兩個資料點(A 和 D),兩個控制點(B 和 C)來描述曲線狀態,如下:
三階曲線計算過程與二階類似,具體可以見下圖動態效果:
PS: 三階曲線對應的方法是cubicTo
貝塞爾曲線速查表
強烈推薦點選這裡練習貝塞爾曲線,可以加深對貝塞爾曲線的理解程度。
第二步.瞭解貝塞爾曲線相關函式使用方法
一階曲線:
一階曲線是一條線段,非常簡單,可以參見上一篇文章Path之基本操作,此處就不詳細講解了。
二階曲線:
通過上面對二階曲線的簡單瞭解,我們知道二階曲線是由兩個資料點,一個控制點構成,接下來我們就用一個例項來演示二階曲線是如何運用的。
首先,兩個資料點是控制貝塞爾曲線開始和結束的位置,比較容易理解,而控制點則是控制貝塞爾的彎曲狀態,相對來說比較難以理解,所以本示例重點在於理解貝塞爾曲線彎曲狀態與控制點的關係,廢話不多說,先上效果圖:
為了更加容易看出控制點與曲線彎曲程度的關係,上圖中繪製出了輔助點和輔助線,從上面的動態圖可以看出,貝塞爾曲線在動態變化過程中有類似於橡皮筋一樣的彈性效果,因此在製作一些彈性效果的時候很常用。
主要程式碼如下:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Bezier</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">View</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Paint mPaint; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> centerX, centerY; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> PointF start, end, control; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Bessel1</span>(Context context) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>(context); mPaint = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Paint(); mPaint.setColor(Color.BLACK); mPaint.setStrokeWidth(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>); mPaint.setStyle(Paint.Style.STROKE); mPaint.setTextSize(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">60</span>); start = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PointF(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); end = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PointF(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); control = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PointF(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onSizeChanged</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> w, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> oldw, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> oldh) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onSizeChanged(w, h, oldw, oldh); centerX = w/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; centerY = h/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 初始化資料點和控制點的位置</span> start.x = centerX-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>; start.y = centerY; end.x = centerX+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>; end.y = centerY; control.x = centerX; control.y = centerY-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>; } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">onTouchEvent</span>(MotionEvent event) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根據觸控位置更新控制點,並提示重繪</span> control.x = event.getX(); control.y = event.getY(); invalidate(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>; } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onDraw</span>(Canvas canvas) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onDraw(canvas); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 繪製資料點和控制點</span> mPaint.setColor(Color.GRAY); mPaint.setStrokeWidth(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>); canvas.drawPoint(start.x,start.y,mPaint); canvas.drawPoint(end.x,end.y,mPaint); canvas.drawPoint(control.x,control.y,mPaint); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 繪製輔助線</span> mPaint.setStrokeWidth(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>); canvas.drawLine(start.x,start.y,control.x,control.y,mPaint); canvas.drawLine(end.x,end.y,control.x,control.y,mPaint); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 繪製貝塞爾曲線</span> mPaint.setColor(Color.RED); mPaint.setStrokeWidth(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>); Path path = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Path(); path.moveTo(start.x,start.y); path.quadTo(control.x,control.y,end.x,end.y); canvas.drawPath(path, mPaint); }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li></ul>
三階曲線:
三階曲線由兩個資料點和兩個控制點來控制曲線狀態。
程式碼:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Bezier2</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">View</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Paint mPaint; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> centerX, centerY; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> PointF start, end, control1, control2; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> mode = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Bezier2</span>(Context context) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>(context, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Bezier2</span>(Context context, AttributeSet attrs) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>(context, attrs); mPaint = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Paint(); mPaint.setColor(Color.BLACK); mPaint.setStrokeWidth(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>); mPaint.setStyle(Paint.Style.STROKE); mPaint.setTextSize(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">60</span>); start = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PointF(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); end = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PointF(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); control1 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PointF(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); control2 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PointF(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setMode</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> mode) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.mode = mode; } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onSizeChanged</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> w, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> oldw, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> oldh) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onSizeChanged(w, h, oldw, oldh); centerX = w / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; centerY = h / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 初始化資料點和控制點的位置</span> start.x = centerX - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>; start.y = centerY; end.x = centerX + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>; end.y = centerY; control1.x = centerX; control1.y = centerY - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>; control2.x = centerX; control2.y = centerY - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>; } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">onTouchEvent</span>(MotionEvent event) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根據觸控位置更新控制點,並提示重繪</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mode) { control1.x = event.getX(); control1.y = event.getY(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { control2.x = event.getX(); control2.y = event.getY(); } invalidate(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>; } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onDraw</span>(Canvas canvas) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onDraw(canvas); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//drawCoordinateSystem(canvas);</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 繪製資料點和控制點</span> mPaint.setColor(Color.GRAY); mPaint.setStrokeWidth(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>); canvas.drawPoint(start.x, start.y, mPaint); canvas.drawPoint(end.x, end.y, mPaint); canvas.drawPoint(control1.x, control1.y, mPaint); canvas.drawPoint(control2.x, control2.y, mPaint); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 繪製輔助線</span> mPaint.setStrokeWidth(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>); canvas.drawLine(start.x, start.y, control1.x, control1.y, mPaint); canvas.drawLine(control1.x, control1.y,control2.x, control2.y, mPaint); canvas.drawLine(control2.x, control2.y,end.x, end.y, mPaint); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 繪製貝塞爾曲線</span> mPaint.setColor(Color.RED); mPaint.setStrokeWidth(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>); Path path = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Path(); path.moveTo(start.x, start.y); path.cubicTo(control1.x, control1.y, control2.x,control2.y, end.x, end.y); canvas.drawPath(path, mPaint); }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li></ul>
三階曲線相比於二階曲線可以製作更加複雜的形狀,但是對於高階的曲線,用低階的曲線組合也可達到相同的效果,就是傳說中的降階。因此我們對貝塞爾曲線的封裝方法一般最高只到三階曲線。
降階與升階
型別 | 釋義 | 變化 |
---|---|---|
降階 | 在保持曲線形狀與方向不變的情況下,減少控制點數量,即降低曲線階數 | 方法變得簡單,資料點變多,控制點可能減少,靈活性變弱 |
升階 | 在保持曲線形狀與方向不變的情況下,增加控制點數量,即升高曲線階數 | 方法更加複雜,資料點不變,控制點增加,靈活性變強 |
第三步.貝塞爾曲線使用例項
在製作這個例項之前,首先要明確一個內容,就是在什麼情況下需要使用貝塞爾曲線?
需要繪製不規則圖形時? 當然不是!目前來說,我覺得使用貝塞爾曲線主要有以下幾個方面(僅個人拙見,可能存在錯誤,歡迎指正)
序號 | 內容 | 用例 |
---|---|---|
1 | 事先不知道曲線狀態,需要實時計算時 | 天氣預報氣溫變化的平滑折線圖 |
2 | 顯示狀態會根據使用者操作改變時 | QQ小紅點,模擬翻書效果 |
3 | 一些比較複雜的運動狀態(配合PathMeasure使用) | 複雜運動狀態的動畫效果 |
至於只需要一個靜態的曲線圖形的情況,用圖片豈不是更好,大量的計算會很不划算。
如果是顯示SVG向量圖的話,已經有相關的解析工具了(內部依舊運用的有貝塞爾曲線),不需要手動計算。
貝塞爾曲線的主要優點是可以實時控制曲線狀態,並可以通過改變控制點的狀態實時讓曲線進行平滑的狀態變化。
接下來我們就用一個簡單的示例讓一個圓漸變成為心形:
效果圖:
思路分析:
我們最終的需要的效果是將一個圓轉變成一個心形,通過分析可知,圓可以由四段三階貝塞爾曲線組合而成,如下:
心形也可以由四段的三階的貝塞爾曲線組成,如下:
相關推薦
Android自定義View進階 - 貝塞爾曲線
Path之貝塞爾曲線 作者微博: @GcsSloop 【本系列相關文章】 在
Android自定義View阻尼動畫&貝塞爾曲線的實現
效果圖:直接上程式碼啦:package com.example.administrator.myapplication.customview; import android.animation.Animator; import android.animation.Anim
025.自定義View中應用貝塞爾曲線
之前一直看QQ的未讀訊息拖拽消失設計得很好,我一直覺得那個設計很好,他們的UI是真心強,於是,我也一直想寫個一樣的玩意來玩玩。最近剛好在複習View相關的知識,就拿這個來練手,下面先來看實現的效果圖: 這是我希望實現的效果,這個效果的實現在第二個圖能看出一點端倪。這裡面的曲線繪製,
Android自定義view進階-- 神奇的貝塞爾曲線
上一篇介紹了自定義view需要知道的基本函式。新開一篇獻給借給我vpn的深圳_奮鬥小哥。 轉載請註明出處:http://blog.csdn.net/wingichoy/article/details/50492828 今天給大家介紹一個非常神奇的曲線,貝塞爾曲線。相信大
Android自定義View進階:分類與流程
經歷過前面三篇囉囉嗦嗦的基礎篇之後,終於到了進階篇,正式進入解析自定義View的階段。 前言 本章節為什麼要叫進階篇?(雖然講的是基礎內容),因為從本篇開始,將會逐漸揭開自定義View的神祕面紗,每一篇都將比上一篇內容更加深入,利用所學的知識能夠製作更加炫酷自定義View,就像
安卓自定義View進階-Path之貝塞爾曲線
在上一篇文章Path之基本操作中我們瞭解了Path的基本使用方法,本次瞭解Path中非常非常非常重要的內容-貝塞爾曲線。 一.Path常用方法表 為了相容性(偷懶) 本表格中去除了在API21(即安卓版本5.0)以上
安卓自定義 View 進階:貝塞爾曲線
在上一篇文章Path之基本圖形中我們瞭解了Path的基本使用方法,本次瞭解Path中非常非常非常重要的內容-貝塞爾曲線。 一.Path常用方法表 為了相容性(偷懶) 本表格中去除了在API21(即安卓版本5.0)以上才新增的方法。忍不住吐槽一下,為啥看起來有些順手就能寫的
安卓自定義View進階-手勢檢測(GestureDecetor)
Android 手勢檢測,主要是 GestureDetector 相關內容的用法和注意事項,本文依舊屬於事件處理這一體系,部分內容會涉及到之前文章提及過的知識點,如果你沒看過之前的文章,可以到 自定義 View 系列 來檢視這些內容。 在開發 Android 手機應用過程中,可
安卓自定義View進階-多點觸控詳解
Android 多點觸控詳解,在前面的幾篇文章中我們大致瞭解了 Android 中的事件處理流程和一些簡單的處理方案,本次帶大家瞭解 Android 多點觸控相關的一些知識。 多點觸控 ( Multitouch,也稱 Multi-touch ),即同時接受螢幕上多個點的人機互動
安卓自定義View進階-特殊控制元件的事件處理方案
本文帶大家瞭解 Android 特殊形狀控制元件的事件處理方式,主要是利用了 Region 和 Matrix 的一些方法,超級實用的事件處理方案,相信看完本篇之後,任何奇葩控制元件的事件處理都會變得十分簡單。 不得不說,Android 對事件體系封裝的非常棒,即便對事件體系不太
安卓自定義View進階-MotionEvent詳解
Android MotionEvent 詳解,之前用了兩篇文章 事件分發機制原理 和 事件分發機制詳解 來講解事件分發,而作為事件分發主角之一的 MotionEvent 並沒有過多的說明,本文就帶大家瞭解 MotionEvent 的相關內容,簡要介紹觸控事件,主要包括 單點觸控、多點
安卓自定義View進階-事件分發機制詳解
Android 事件分發機制詳解,在上一篇文章 事件分發機制原理 中簡要分析了一下事件分發機制的原理,原理是十分簡單的,一句話就能總結:責任鏈模式,事件層層傳遞,直到被消費。 雖然原理簡單,但是隨著 Android 不斷的發展,實際運用場景也越來越複雜,所以想要徹底玩轉事件分發機制還
安卓自定義View進階-Matrix Camera
本篇依舊屬於Matrix,主要講解Camera,Android下有很多相機應用,其中的美顏相機更是不少,不過今天這個Camera可不是我們平時拍照的那個相機,而是graphic包下的Camera,專業給View拍照的相機,不過既然是相機,作用都是類似的,主要是將3D的內容拍扁變成2D
安卓自定義View進階-Matrix詳解
這應該是目前最詳細的一篇講解Matrix的中文文章了,在上一篇文章Matrix原理中,我們對Matrix做了一個簡單的瞭解,偏向理論,在本文中則會詳細的講解Matrix的具體用法,以及與Matrix相關的一些實用技巧。 ⚠️ 警告:測試本文章示例之前請關閉硬體加速。
安卓自定義View進階-Matrix原理
本文內容偏向理論,和 畫布操作 有重疊的部分,本文會讓你更加深入的瞭解其中的原理。 本篇的主角Matrix,是一個一直在後臺默默工作的勞動模範,雖然我們所有看到View背後都有著Matrix的功勞,但我們卻很少見到它,本篇我們就看看它是何方神聖吧。 由於Goog
安卓自定義View進階-PathMeasure
可以看到,在經過 Path之基本操作 Path之貝塞爾曲線 和 Path之完結篇 後, Path中各類方法基本上都講完了,表格中還沒有講解到到方法就是矩陣變換了,難道本篇終於要講矩陣了? 非也,矩陣這一部分仍在後面單獨講解,本篇主要講解 PathMeasure 這個類與 Path 的
安卓自定義View進階-Path之基本操作
在上一篇Canvas之圖片文字中我們瞭解瞭如何使用Canvas中繪製圖片文字,結合前幾篇文章,Canvas的基本操作已經差不多完結了,然而Canvas不僅僅具有這些基本的操作,還可以更加炫酷,本次會了解到path(路徑)這個Canvas中的神器,有了這個神器,就能創造出更多炫(zhu
安卓自定義View進階-Canvas之圖片文字
在上一篇文章Canvas之畫布操作中我們瞭解了畫布的一些基本操作方法,本次瞭解一些繪製圖片文字相關的內容。如果你對前幾篇文章講述的內容熟練掌握的話,那麼恭喜你,本篇結束之後,大部分的自定義View已經難不倒你了,當然了,這並不是終點,接下來還會有更加炫酷的技能。 一.Canva
安卓自定義View進階-分類與流程
本章節為什麼要叫進階篇?(雖然講的是基礎內容),因為從本篇開始,將會逐漸揭開自定義View的神祕面紗,每一篇都將比上一篇內容更加深入,利用所學的知識能夠製作更加炫酷自定義View,就像在臺階上一樣,每一篇都更上一層,幫助大家一步步走向人生巔峰,出任CEO,迎娶白富美。 誤
安卓自定義View進階-Path之完結篇
經歷過前兩篇 Path之基本操作 和 Path之貝塞爾曲線 的講解,本篇終於進入Path的收尾篇,本篇結束後Path的大部分相關方法都已經講解完了,但Path還有一些更有意思的玩法,應該會在後續的文章中出現。 一.Path常用方法表 為了相容性(偷懶) 本表格中去除