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方法等價。