1. 程式人生 > >Path類常用API介紹

Path類常用API介紹

/**
 * The Path class encapsulates compound (multiple contour) geometric paths consisting of straight line segments, quadratic curves, and cubic curves.
 * It can be drawn with canvas.drawPath(path, paint), either filled or stroked
 * (based on the paint's Style), or it can be used for clipping or to
draw * text on a path. */

翻譯: Path封裝了由直線和曲線(二次,三次貝塞爾曲線)構成的幾何路徑。你能用Canvas中的drawPath來把這條路徑畫出來(同樣支援Paint的不同繪製模式),也可以用於剪裁畫布和根據路徑繪製文字。我們有時會用Path來描述一個影象的輪廓,所以也會稱為輪廓線(輪廓線僅是Path的一種使用方法,兩者並不等價)。

從註釋中可以看出,Path類封裝了一些複合的幾何路徑,其中包括直線,二次曲線,三次曲線等,以及做圖表什麼的都可以。我們來看一下他的原始碼,其中有一個內部類Direction,在我們呼叫Path的一系列add方法往Path裡面新增圖形的時候,就會需要提供一個方向,比如我們呼叫addRect方法新增一個矩形Rect(100,100,200,200)的時候,假設該矩形的四個頂點為ABCD,座標分別為A(100,100),B(200,100),C(200,200),D(200,100),在add到Paht裡的時候,Path會根據指定的方向,來解析每個點構成的直線,如果指定的方向是順時針的話,則矩形的四條邊新增和繪製的順序依次是AB,BC,CD,DA;如果是逆時針的話,則依次為AD,DC,CB,BA,下面會通過程式碼例項來驗證我們的想法。

Direction的原始碼如下:

/**
* Specifies how closed shapes (e.g. rects, ovals) are oriented when they
* are added to a path.
*/
public enum Direction {
/** 順時針方向*/
CW  (0),    // must match enum in SkPath.h
/** 逆時針方向 */
CCW (1);    // must match enum in SkPath.h

Direction(int ni) {
    nativeInt = ni;
}
final int
nativeInt; }

測試程式碼如下:

mPath.addRect(200, 100, 500, 300, Path.Direction.CW);
canvas.drawPath(mPath, mPaint);
mPath.reset();
mPath.addRect(200, 400, 500, 600, Path.Direction.CCW);
canvas.drawPath(mPath, mPaint);

效果圖如下:
這裡寫圖片描述
從實現的效果圖中,我們發現,在繪製規則圖形的時候,順時針和逆時針基本沒有差別,為了看出差異,我們修改一下上面的程式碼如下:

setLayerType(LAYER_TYPE_SOFTWARE, null);//需要關閉硬體加速功能,否則畫出的形狀是不閉合的,

mPath.addRect(100, 100, 300, 300, Path.Direction.CW);
mPath.setLastPoint(50, 200);
mPath.close();
canvas.drawPath(mPath, mPaint);

mPath.reset();
mPath.addRect(100, 400, 300, 600, Path.Direction.CCW);
mPath.setLastPoint(50, 500);
mPath.close();//使圖形閉合
canvas.drawPath(mPath, mPaint);

實現效果如下:
這裡寫圖片描述

當我們指定最後一個繪製點的時候,順時針和逆時針就可以看出差異了。

當我們在指定的路徑上畫文字的時候,文字的方向就會跟我們新增的路徑時所使用的方向保持一致。
如:

mPath.addCircle(400, 400, 300, Path.Direction.CW);
canvas.drawPath(mPath, mPaint);
canvas.drawTextOnPath("順時針方向繪製文字", mPath, 25, 25, mPaint);

mPath.reset();
mPath.addCircle(400, 1100, 300, Path.Direction.CCW);
canvas.drawPath(mPath, mPaint);
canvas.drawTextOnPath("逆時針方向繪製文字", mPath, 25, 25, mPaint);

效果圖如下:
這裡寫圖片描述

上面介紹了一下Path.Direction類的基本用法,接下來就介紹Path常用Api。

Path常用Api簡述:

方法名稱 方法描述
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 分別為新增二階和三階貝塞爾曲線的方法
rMoveTo, rLineTo, rQuadTo, rCubicTo 不帶r的方法是基於原點的座標系(偏移量), rXxx方法是基於當前點(即以當前點為座標原點)座標系(偏移量)
setFillType, getFillType, isInverseFillType, toggleInverseFillType 設定,獲取,判斷和切換填充模式
incReserve 提示Path還有多少個點等待加入(這個方法貌似會讓Path優化儲存結構)
op 對兩個Path進行布林運算(即取交集、並集等操作)
computeBounds 計算Path的邊界
reset, rewind 清除Path中的內容,reset不保留內部資料結構,但會保留FillType;rewind會保留內部的資料結構,但不保留FillType
transform 矩陣變換

Path常用Api例項詳解

在UI繪製的時候,硬體加速在某些情況下會引起一些繪製問題,如上面的繪製,在沒有關閉硬體加速的時候,繪製的圖形是不閉合的,所以為了避免不必要的麻煩,在繪製之前關閉硬體加速,關閉的方式有如下幾種方式:

  • setLayerType(LAYER_TYPE_SOFTWARE, null);在自定義控制元件初始化的時候設定
  • 在AndroidMenifest檔案中application節點下添上 android:hardwareAccelerated=”false”

Path新增圓弧的方法:addArc,arcTo

// addArc
public void addArc (RectF oval, float startAngle, float sweepAngle);
// arcTo
public void arcTo (RectF oval, float startAngle, float sweepAngle);
/**
 * Append the specified arc to the path as a new contour. If the start of
 * the path is different from the path's current last point, then an
 * automatic lineTo() is added to connect the current contour to the
 * start of the arc. However, if the path is empty, then we call moveTo()
 * with the first point of the arc.
 *
 * @param startAngle  開始角度
 * @param sweepAngle  偏移角度,即繪製多少角度的圓弧
 * @param forceMoveTo true把
 */
public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)

註釋翻譯:新增一個指定的圓弧到Path中,如果被新增的圓弧的起點與當前Path路徑的最後一個點不相同,那麼將會自動的呼叫lineTo方法,把前路徑最後一個點與圓弧的起點用直線連線起來。如果當前Path為空,則呼叫moveTo方法,把圓弧的第一個點設定為起點。

通過註釋我們可以瞭解到,如果forceMoveTo引數為true,那麼會呼叫moveTo方法把被圓弧的起點設定為當前路徑的最後一個點,這樣當前Path路徑的最後一個點的座標與被新增圓弧的起點座標是一樣的,這樣就不會呼叫lineTo方法去連線了,如果forceMoveTo引數為false,那麼當前Path路徑的最後一個點沒有改變,該是啥就是啥,如果與被新增的圓弧起點不一致,則會呼叫lineTo方法新增一條連線,把當前Path的最後一個點與圓弧的起點連線起來。預設為false。

例項程式碼:

Path path = new Path();
path.lineTo(100, -100);
path.arcTo(new RectF(-300, -300, -100, -100), 0, 270);//
path.arcTo(new RectF(-50, -50, 100, 100), 0, 270, true);
canvas.drawPath(path, paint);

效果圖如下:
這裡寫圖片描述

說明:

  • path.lineTo(100, -100);方法添加了一條直線1,執行完後,Path的最後一個點為A,
  • path.arcTo(new RectF(-300, -300, -100, -100), 0, 270);向Path中添加了一個圓弧2,arcTo方法預設forceMoveTo引數為false,所以在執行arcTo方法的時候,發現當前Path的最後一個點是A,但被新增的圓弧2的起點B與A的座標不一致,所以會呼叫lineTo方法,把A和B兩點連線起來,於是就有了線條4。執行順序:先畫直線4,在畫圓弧2。所以執行完該程式碼後,Path的最後一個點為C。
  • path.arcTo(new RectF(-50, -50, 100, 100), 0, 270, true);向Path中新增一個圓弧3,此時forceMoveTo引數為true,則會先呼叫moveTo方法(引數為D的座標),這時當前Path的最後一個點的就變成了D,與圓弧3的起點座標是一樣的,所以就沒有在呼叫lineTo方法去畫直線了。執行完該程式碼後,當前Path的最後一個點為E。

總結:addArc就是簡單的新增一條圓弧,當arcTo方法方法的forceMoveTo=true的時候,與addArc方法等價。