【轉載】Android繪圖之Path總結

Path做爲Android中一種相對複雜的繪圖方式,官方文檔中的有些解釋並非很好理解,這裏做一個相對全面一些的總結,供往後查看,也分享給你們,共同進步。java

1.基本繪圖方法

  1. addArc(RectF oval, float startAngle, float sweepAngle)
    繪製弧線,配合Paint的Style能夠實現不一樣的填充效果
  2. addCircle(float x, float y, float radius, Path.Direction dir)
    繪製圓形,其中第dir參數用來指定繪製時是順時針仍是逆時針
  3. addOval(RectF oval, Path.Direction dir)
    繪製橢圓形,其中 oval做爲橢圓的外切矩形區域
  4. addRect(RectF rect, Path.Direction dir)
    繪製矩形
  5. addRoundRect(RectF rect, float rx, float ry, Path.Direction dir)
    繪製圓角矩形
  6. lineTo(float x, float y)
    繪製直線
  7. addPath(Path src)
    添加一個新的Path到當前Path
  8. arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
    addArc方法類似,但也有區別,下文細述。
  9. quadTo(float x1, float y1, float x2, float y2)
    繪製二次貝塞爾曲線,其中 (x1,y1)爲控制點,(x2,y2)爲終點
  10. cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
    繪製三次貝塞爾曲線,其中(x1,y1),(x2,y2)爲控制點,(x3,y3)爲終點

2.rXXX方法

上面的lineTo,MoveTo,QuadTo,CubicTo方法都有與之對應的rXXX方法:算法

  1. rLineTo(float dx, float dy)
  2. rMoveTo(float dx, float dy)
  3. rQuadTo(float dx1, float dy1, float dx2, float dy2)
  4. rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)

這些方法與之對應的原方法相比,唯一的區別在於:r方法是基於當前繪製開始點的offest,好比當前paint位於 (100,100)處,則使用rLineTo(100,100)方法繪製出來的直線是從(100,100)到(200,200)的一條直接,因而可知rXXX方法方便用來基於以前的繪製做連續繪製。canvas

3.Path.op方法

//原型
op(Path path, Path.Op op) //eg path1.op(path2,Path.Op.DIFFERENCE);

此方法用於對兩個Path對象作相應的運算組合(combine),具體的說是根據不一樣的op參數及path2參數來影響path1對象,有點相似於數學上的集合運算。請看下面的例子:swift

Path path1 = new Path();
path1.addCircle(150, 150, 100, Path.Direction.CW); Path path2 = new Path(); path2.addCircle(200, 200, 100, Path.Direction.CW); path1.op(path2, Path.Op.DIFFERENCE); canvas.drawPath(path1, paint1);

效果以下:
數據結構

經過不斷修改path1.op的第二個參數依次能夠獲得以下效果:ide

Path.Op.INTERSECT效果:
動畫

Path.Op.UNION效果:
ui

Path.Op.REVERSE_DIFFERENCE效果:spa

Path.Op.XOR效果:rest

總結:

  1. Path.Op.DIFFERENCE 減去path1中path1與path2都存在的部分;
    path1 = (path1 – path1 ∩ path2)
  2. Path.Op.INTERSECT 保留path1與path2共同的部分;
    path1 = path1 ∩ path2
  3. Path.Op.UNION 取path1與path2的並集;
    path1 = path1 ∪ path2
  4. Path.Op.REVERSE_DIFFERENCE 與DIFFERENCE恰好相反;
    path1 = path2 – (path1 ∩ path2)
  5. Path.Op.XOR 與INTERSECT恰好相反;
    path1 = (path1 ∪ path2) – (path1 ∩ path2)

4.setFillType

設置path的填充模式.網上關於path的FillType的介紹不多,實際上在官方ApiDemos裏就有個很好的例子:

/**
 * Created by ghui on 10/25/15.
 */
public class PathFillTypeView extends View { private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Path mPath; public PathFillTypeView(Context context) { super(context); setFocusable(true); setFocusableInTouchMode(true); mPath = new Path(); mPath.addCircle(40, 40, 45, Path.Direction.CCW); mPath.addCircle(80, 80, 45, Path.Direction.CCW); mPath.addCircle(120, 120, 45, Path.Direction.CCW); } private void showPath(Canvas canvas, int x, int y, Path.FillType ft, Paint paint) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, 160, 160); canvas.drawColor(Color.WHITE); mPath.setFillType(ft); canvas.drawPath(mPath, paint); canvas.restore(); } @Override protected void onDraw(Canvas canvas) { Paint paint = mPaint; paint.setColor(Color.RED); canvas.drawColor(0xFFCCCCCC); canvas.translate(20, 20); paint.setAntiAlias(true); showPath(canvas, 0, 0, Path.FillType.WINDING, paint); showPath(canvas, 160 * 2, 0, Path.FillType.EVEN_ODD, paint); showPath(canvas, 0, 160 * 2, Path.FillType.INVERSE_WINDING, paint); showPath(canvas, 160 * 2, 160 * 2, Path.FillType.INVERSE_EVEN_ODD, paint); } }

效果以下:


(上面的例子在官方ApiDemo的基礎上作了適當的修改)

總結:

所謂填充指的就是填充內部,setFillType就是用來界定哪裏算內部的算法。在計算機圖形學中界定一個點是否是在多邊形內部有兩種算法:

  1. 非零環繞數規則(Nonzero-rule)
  2. 奇偶規則(Even–odd rule)

關於這兩種算法這裏不做詳細介紹。

5.易混淆的方法

1. addArc 與 arcTo

前者指定在某處畫一條弧線,僅此而已,不會受當前paint的位置所影響。而arcTo方法有兩種形式:

  1. arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
  2. arcTo(RectF oval, float startAngle, float sweepAngle)對於第一種形式的方法,若forceMoveTo參數爲false,則與第二種形式的方法沒區別,繪製成的最終圖形會受到落筆點的影響;
    若forceMoveTo參數值爲true,則繪製效果與addArc方法沒有區別。
//代碼1
Path path = new Path(); path.moveTo(100, 100); path.addArc(200, 200, 400, 400, 0, 150); canvas.drawPath(path, paint);

代碼1效果以下圖:

//代碼2
Path path = new Path(); path.moveTo(100, 100); path.arcTo(200, 200, 400, 400, 0, 150, false); canvas.drawPath(path,paint);

代碼2效果以下圖:

若將代碼2中的arcTo方法的參數修改成true則繪製的效果與代碼1相同。

2. reset 與 rewind

reset清除path上的內容,重置path到 path = new Path()的初始狀態。
rewind清除path上的內容,但會保留path上相關的數據結構,以高效的複用。

其它方法

  1. moveTo(float x,float y)
    移動畫筆到 (x,y) 處
  2. offset(float dx, float dy)
    平移當前path,在此path上繪製的任何圖形都會受到影響
  3. close()
    閉合當前路徑 (系統會自動從起點到終點繪製一條直線,使當前路徑閉合)
  4. reset()
    重置path,但不會重置fill-type設置
  5. rewind()
    重置path,但會保留內部數據結構
  6. set(Path src)
    設置新的Path到當前對象
  7. setLastPoint(float x,float y)
    設置當前path的終點
  8. transform(Matrix matrix)矩陣變換
相關文章
相關標籤/搜索