自定義view(14)使用Path繪製複雜圖形

 

靈活使用 Path ,能夠畫出複雜圖形,就像美術生在畫板上畫複雜圖形同樣。程序員也能夠用代碼實現。android

1.樣板圖片

這個是個溫度計,它是靜態的,溫度值是動態變化的,因此要自定義個view.動態顯示值,溫度太高、太低時有警示功能。git

2.代碼

  https://github.com/f9q/tempView程序員

3.Path類的關鍵api

3.1 絕對繪製系列

  • void moveTo(float x, float y)

    將畫筆移動到x,ygithub

  • void lineTo(float x, float y)

    鏈接當前點到目標點dp(x,y),畫一條線。算法

  • void arcTo(RectF oval, float startAngle, float sweepAngle)

    從當前點開始畫弧,startAngle是順時針起始角度,sweepAngle是掃過角度(按360求模)。若是oval的起點不是當前path的最後一個點,則鏈接最後一個點到oval的起點。api

  • void quadTo(float x1, float y1, float x2, float y2)

    假設最後個點是op(10,20),若是沒有用MoveTo指定,默認點是(0,0),畫一條通過 op、控制點cp(x1,y1)、終點ep(x2,y2)的貝塞爾曲線. 數組

  • void cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

    與quadTo類似,只不過多個控制點cp2(x2,y2)app

3.2 相對繪製系列

  •  void rMoveTo(float dx, float dy)

    假設前個點是op(10,20),將畫筆移動到目標點dp(dx,dy), 其中dx是相對10的偏移量,dy是相對20的偏移量。dom

  •  void rLineTo(float dx, float dy)

    假設前個點是op(10,20), 鏈接當前點到目標點dp(dx,dy),畫一條線。其中dx是相對10的偏移量,dy是相對20的偏移量ide

  • void rQuadTo(float dx1, float dy1, float dx2, float dy2)

    假設前個點是op(10,20),默認點是(0,0),畫一條通過op、控制點cp(dx1,dy1)、終點ep(dx2,dy2)的貝塞爾曲線。dx1,dx2是相對前個點10的x偏移量,可爲負。

dy1,dy2是相對前個點20的y偏移量,可爲負。

  • void rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)

    與rQuadTo類似。也是多個了個控制點cp2(x2,y2)

3.3 添加圖形系列

  • void addRect(RectF rect, Direction dir)

    在路徑上添加一個矩形、第2個參數是添加矩形的繪製方向,

    • Direction.CW 順時針
    • Direction.CCW 逆時針
  • void addRoundRect(RectF rect, float rx, float ry, Direction dir)

    與上一個類似,添加的是圓角矩形。dir是縱向方向,如上。

  • void addOval(RectF oval, Direction dir) 

    添加一個橢圓,dir是縱向方向,如上。

  • void addCircle(float x, float y, float radius, Direction dir)

    添加一個圓圈,radius半徑,dir是縱向方向。如上。

  • void addArc(RectF oval, float startAngle, float sweepAngle)

    添加一個弧線,startAngle是順時針起始角度,sweepAngle是掃過角度(按360求模)。

  • void addPath(Path src, float dx, float dy) 

    在當前路徑上添加一個新的路徑,dx,dy是相對最後一個點的x,y偏移量。

3.4 路徑設置系列

  • void transform(Matrix matrix, Path dst)

    把當前路徑按matrix變形,若是dst不空,複製一分到dst中。

  • void reset()

    清空path對象數據和軌跡。保留FillType。

  • void rewind()

  清空所繪製的軌跡,但保留對象內部數據。方便下次快速複用。 不保留FillType。

  • void setFillType(FillType ft) 

  這個比較複雜,見5.path.setFillType(FillType ft) 

  • void close()

    閉合路徑,若是執行閉合操做時當前點不和第1個點重合,則會畫出一條線。

  • void offset(float dx, float dy)

    當前路徑總體(全部圖形)平移。

4.Path特效

  能夠給path添加各類特效,如虛線,離散等等。

4.1 未指定特效的樣子

 

4.2 CornerPathEffect

效果:將路徑的轉角變成圓角。

 

代碼:

1    paint.setPathEffect(new CornerPathEffect(30));

參數:

  圓角的半徑。

4.3 DiscretePathEffect

效果:離散路徑。

代碼:

1   paint.setPathEffect(new DiscretePathEffect(3.0f, 10.0f));

參數:

    /**
     * Chop the path into lines of segmentLength, randomly deviating from the
     * original path by deviation.
     */
  • 第1個參數是橫向兩個離散點的間距。
  • 第2個參數是縱向隨機離散的最大距離。

4.4 DashPathEffect

效果:虛線效果。

 

代碼:

1     float intervals[] = {1,5,10,15};
2     paint.setStrokeWidth(5);
3     paint.setStyle(Paint.Style.STROKE);
4     paint.setPathEffect(new DashPathEffect(intervals, 3));

DashPathEffect參數的含義:

     /**
     * The intervals array must contain an even number of entries (>=2), with
     * the even indices specifying the "on" intervals, and the odd indices
     * specifying the "off" intervals. phase is an offset into the intervals
     * array (mod the sum of all of the intervals). The intervals array
     * controls the length of the dashes. The paint's strokeWidth controls the
     * thickness of the dashes.
     * Note: this patheffect only affects drawing with the paint's style is set
     * to STROKE or FILL_AND_STROKE. It is ignored if the drawing is done with
     * style == FILL.
     * @param intervals array of ON and OFF distances
     * @param phase offset into the intervals array
     */
  • 第1個參數

    控制虛線的長度與間隙,數組長度不能小於2個,偶數位表示實線線段的長度(上面數組中的一、10),奇數位表示間隙的長度(上面數組中的五、15)。

  • 第2個參數

    控制虛線第1段是線段仍是間隙,按第1個參數的長度求模。

  注意:這個特效只有在 paint的風格是 STROKE 和 FILL_AND_STROKE 時有效。

4.5 PathDashPathEffect

效果:指定虛線上的每一個線段的圖形爲另外一個路徑。

代碼:

1     Path rectDash = new Path();
2     rectDash.addRect(0, 0, 10,10, Path.Direction.CW);
3     paint.setPathEffect(new PathDashPathEffect(rectDash,20,1, PathDashPathEffect.Style.MORPH));

參數:

  • 第1個參數是虛線段的圖形。
  • 第2個參數是間隙的距離。
  • 第3個參數指定路徑的下標。
  • 第4個參數是圖形路徑的繪製樣式。有
    MORPH、ROTATE、TRANSLATE 3種。

4.6 ComposePathEffect

效果:組合效果

代碼:

1         float intervals[] = {1,5,10,15};
2         DiscretePathEffect discrete = new DiscretePathEffect(3.0f, 10.0f);
3         DashPathEffect dash = new DashPathEffect(intervals, 3) ;
4         ComposePathEffect compose = new ComposePathEffect(discrete,dash);
5         paint.setPathEffect(compose);

參數:

    /**
     * Construct a PathEffect whose effect is to apply first the inner effect
     * and the the outer pathEffect (e.g. outer(inner(path))).
     */
    public ComposePathEffect(PathEffect outerpe, PathEffect innerpe) {
        native_instance = nativeCreate(outerpe.native_instance,
                                       innerpe.native_instance);
    }

  第1個路徑和第2個路徑。先畫出innerpe的效果,接着在innerpe的基礎上增長outerpe效果!

4.7 SumPathEffect

效果:疊加效果

代碼:

1         float intervals[] = {1,5,10,15};
2         DiscretePathEffect discrete = new DiscretePathEffect(3.0f, 10.0f);
3         DashPathEffect dash = new DashPathEffect(intervals, 3) ;
4         SumPathEffect sum = new SumPathEffect(discrete,dash);
5         paint.setPathEffect(sum);

參數:

    /**
     * Construct a PathEffect whose effect is to apply two effects, in sequence.
     * (e.g. first(path) + second(path))
     */
    public SumPathEffect(PathEffect first, PathEffect second) {
        native_instance = nativeCreate(first.native_instance,
                                       second.native_instance);
    }

  先畫出first的效果,接着繪製second效果!將兩個效果簡單的重疊在一塊兒顯示出來!

5.path.setFillType(FillType ft)

5.1 做用

  它指定計算路徑內部區域的算法。如何判斷點在圖形內外,通常有兩種:奇偶算法和非零環繞數算法。

5.2 相關源碼

 1 /**
 2      * Set the path's fill type. This defines how "inside" is computed.
 3      *
 4      * @param ft The new fill type for this path
 5      */
 6     public void setFillType(FillType ft) {
 7         nSetFillType(mNativePath, ft.nativeInt);
 8     }
 9     /**
10      * Enum for the ways a path may be filled.
11      */
12     public enum FillType {
13         // these must match the values in SkPath.h
14         /**
15          * Specifies that "inside" is computed by a non-zero sum of signed
16          * edge crossings.
17          */
18         WINDING         (0),
19         /**
20          * Specifies that "inside" is computed by an odd number of edge
21          * crossings.
22          */
23         EVEN_ODD        (1),
24         /**
25          * Same as {@link #WINDING}, but draws outside of the path, rather than inside.
26          */
27         INVERSE_WINDING (2),
28         /**
29          * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
30          */
31         INVERSE_EVEN_ODD(3);
32 
33         FillType(int ni) {
34             nativeInt = ni;
35         }
36 
37         final int nativeInt;
38     }

5.3 FillType含義表

EVEN_ODD 奇偶算法
INVERSE_EVEN_ODD 反奇偶算法
WINDING 非零環繞數算法
INVERSE_WINDING 反非零環繞數算法

5.4 奇偶算法

算法:

  從p點向任意方向做一條射線, 若該射線與圖形相交的邊數爲奇數,則p是圖形內部點,不然是外部點。

示例:

 

紅色的點在多邊形內部。從它出發做任意射線(圖中畫出了兩種可能),它與多邊形的邊一定相交奇數次(圖中兩條射線分別相交1次和3次)。

藍色的點在多邊形外部。從它出發做任意射線(圖中畫出了兩種可能),它與多邊形的邊一定相交偶數次(圖中兩條射線分別相交0次和2次)。

5.5 非零環繞數

算法:該方法經常使用與判斷點是否在多邊形或曲線上。
  使多邊形的邊變爲矢量。將環繞數初始化爲零。從點p向外作一條射線(能夠任意方向),多邊形的邊從左到右通過射線時環數減1,多邊形的邊從右往左通過射線時環數加1,最後環數不爲0,即表示在多邊形內部,反之在外部。

示例:

  • 5角星上的箭頭表示邊的方向
  • 從p點向右下做一條射線
  • 環繞數WindingNumber,初始值爲0,
  • 從上到下,這裏有3條邊與射線相交。
  • 第1條邊方向是 -->,WindingNumber -= 1
  • 第2條邊方向是 <--,WindingNumber += 1
  • 第3條邊方向是 <--,WindingNumber += 1
  • 最終WindingNumber = 1,值非0,則在圖形內。

6.路徑之間的運算(求交集、並集等)

6.1 Path.op(xxx)

源碼:與其它path進行運算。它還有一個重載版本。

 1     /**
 2      * Set this path to the result of applying the Op to the two specified paths.
 3      * The resulting path will be constructed from non-overlapping contours.
 4      * The curve order is reduced where possible so that cubics may be turned
 5      * into quadratics, and quadratics maybe turned into lines.
 6      *
 7      * @param path1 The first operand (for difference, the minuend)
 8      * @param path2 The second operand (for difference, the subtrahend)
 9      *
10      * @return True if operation succeeded, false otherwise and this path remains unmodified.
11      *
12      * @see Op
13      * @see #op(Path, android.graphics.Path.Op)
14      */
15     public boolean op(Path path1, Path path2, Op op) {
16         if (nOp(path1.mNativePath, path2.mNativePath, op.ordinal(), this.mNativePath)) {
17             isSimplePath = false;
18             rects = null;
19             return true;
20         }
21         return false;
22     }
23     /**
24      * The logical operations that can be performed when combining two paths.
25      *
26      * @see #op(Path, android.graphics.Path.Op)
27      * @see #op(Path, Path, android.graphics.Path.Op)
28      */
29     public enum Op {
30         /**
31          * Subtract the second path from the first path.
32          */
33         DIFFERENCE,
34         /**
35          * Intersect the two paths.
36          */
37         INTERSECT,
38         /**
39          * Union (inclusive-or) the two paths.
40          */
41         UNION,
42         /**
43          * Exclusive-or the two paths.
44          */
45         XOR,
46         /**
47          * Subtract the first path from the second path.
48          */
49         REVERSE_DIFFERENCE
50     }

參數:前兩個參數是參與運算的path,第3個參數是路徑運算符。

6.2 路徑運算符

運算符 類比集合運算 說明 示意圖
XOR 異或 求非交集。
INTERSECT 交集 Path1與Path2相交的部分
UNION 並集 包含所有Path1和Path2
DIFFERENCE 差集 Path1中減去Path2後剩下的部分
REVERSE_DIFFERENCE 差集 Path2中減去Path1後剩下的部分
相關文章
相關標籤/搜索