Android繪圖之Path(3)

Android 繪圖學(xué)習(xí)

1 Path 簡(jiǎn)介

前面利用Paint,Canvas已經(jīng)可以繪制出各式各樣的簡(jiǎn)單圖形了,本篇講解Path意為路徑,canvas中有drawPath函數(shù)按照路徑繪制圖形。利用Path可以更方便的添加節(jié)點(diǎn),控制形狀,對(duì)于復(fù)雜的形狀簡(jiǎn)單的通過(guò)Canvas的繪制函數(shù)進(jìn)行繪制繁瑣且麻煩,使用Path可能會(huì)簡(jiǎn)化操作,一般復(fù)雜的圖形都是用Path進(jìn)行繪制。

注意: 關(guān)于網(wǎng)上流傳的開(kāi)啟硬件加速對(duì)二維繪圖(自定義控件繪制)的影響,這里不討論,也不關(guān)閉硬件加速,硬件加速的確會(huì)影響繪制這時(shí)由于API中的某些函數(shù)不支持硬件加速(因?yàn)殚_(kāi)啟和不開(kāi)啟硬件加速走的繪制過(guò)程有所差異),所以需要關(guān)閉硬件加速才能起效果。
相關(guān)硬件加速請(qǐng)查閱:https://developer.android.com/guide/topics/graphics/hardware-accel

1.1 Path類(lèi)的注釋

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可用于繪制直線(xiàn),曲線(xiàn)構(gòu)成幾何路徑,還可以用于剪裁畫(huà)布和根據(jù)路徑繪制文字。
Paint的繪制模式設(shè)置成stroke更能顯示效果。

1.2 構(gòu)造函數(shù):

Path()
創(chuàng)建一個(gè)空的Path

Path(Path src)
利用已有Path生成新Path。

2 直線(xiàn)路徑

Path用于繪制路徑,所以如果是繪制點(diǎn)用不到Path,最簡(jiǎn)單的路徑就是由直線(xiàn)組成,Path提供了簡(jiǎn)單的函數(shù)實(shí)現(xiàn)直線(xiàn)的繪制。
四個(gè)重要函數(shù):

  • moveTo
  • lineTo
  • close
  • setLastPoint
  • rMoveTo
  • rLineTo

moveTo
public void moveTo(float x, float y) ;
moveTo (float x, float y):直線(xiàn)的開(kāi)始點(diǎn)(也可能是下一個(gè)形狀的開(kāi)始點(diǎn))即將直線(xiàn)路徑的繪制位置定在(x,y)的位置;
rMoveTo在前一個(gè)點(diǎn)的基礎(chǔ)上開(kāi)始繪制新的直線(xiàn)。

lineTo
public void lineTo(float x, float y) ;
void lineTo (float x2, float y2):結(jié)束點(diǎn)或者下一次繪制直線(xiàn)路徑的開(kāi)始點(diǎn);
rLineto:在前面路徑的基礎(chǔ)上連續(xù)繪制,如果前面一個(gè)點(diǎn)是(x,y),rLineTo(x1,y1)相當(dāng)于lineTo(x+x1,y+y1),如果前面沒(méi)有調(diào)用moveTo,相當(dāng)于從(0,0)開(kāi)始繪制。

多次調(diào)用lineTo可以一直調(diào)用。如果一個(gè)直線(xiàn)開(kāi)始繪制沒(méi)有調(diào)用moveTo,默認(rèn)第一個(gè)點(diǎn)從(0,0)點(diǎn)開(kāi)始繪制。lineTo添加的是直線(xiàn)而不僅僅是點(diǎn)。

public void close() ;
void close ():如果繪制的直線(xiàn)沒(méi)有形成閉環(huán),調(diào)用Close()會(huì)將路徑首尾點(diǎn)連接起來(lái),形成閉環(huán);

/**
 * Sets the last point of the path.
 *
 * @param dx The new X coordinate for the last point
 * @param dy The new Y coordinate for the last point
 */
public void setLastPoint(float dx, float dy) {
    isSimplePath = false;
    nSetLastPoint(mNativePath, dx, dy);
}

setLastPoint 會(huì)重新設(shè)置最后一個(gè)點(diǎn)的坐標(biāo)。

mPath = new Path();

mPath.moveTo(100,70);
mPath.lineTo(140,180);
mPath.lineTo(250,330);
mPath.lineTo(400,630);
mPath.lineTo(100,830);

未調(diào)用close函數(shù)

調(diào)用了close函數(shù)

多次調(diào)用moveTo可以繪制多條不相關(guān)的線(xiàn)段:

mPath.moveTo(100,70);
mPath.lineTo(140,180);
mPath.lineTo(250,330);
mPath.lineTo(400,630);
mPath.lineTo(100,830);
mPath.moveTo(100,1000);
mPath.lineTo(600,1300);
mPath.lineTo(400,1700);

setLastPoint重置最后一個(gè)點(diǎn)的坐標(biāo)。
mPath.moveTo(100,70);
mPath.lineTo(140,180);
mPath.lineTo(250,330);
mPath.lineTo(400,630);
mPath.lineTo(100,830);
mPath.moveTo(100,1000);
mPath.lineTo(600,1300);
mPath.lineTo(400,1700);
mPath.setLastPoint(300,1700);

3 addArch 添加圓弧路徑1

addArc

public void addArc(RectF oval, float startAngle, float sweepAngle) {
    addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
}

//利用坐標(biāo)點(diǎn)代替RectF
public void addArc(float left, float top, float right, float bottom, float startAngle,
        float sweepAngle) {
    isSimplePath = false;
    nAddArc(mNativePath, left, top, right, bottom, startAngle, sweepAngle);
}

添加圓弧路徑:
oval:矩形區(qū)域
startAngle:開(kāi)始弧度
sweepAngle:弧形掃過(guò)的弧度
x軸正方向?yàn)?度,然后順時(shí)針繪制。

實(shí)例代碼

RectF rectF1 = new RectF(200,200,500,500);
RectF rectF2 = new RectF(200,600,500,900);
mPath.addArc(rectF1,180,180);
mPath.addArc(rectF2,0,270);

4 arcTo 添加圓弧路徑2

和addArc類(lèi)似,添加一個(gè)圓弧到path,如果圓弧的起點(diǎn)和上次最后一個(gè)坐標(biāo)點(diǎn)不相同,就連接兩個(gè)點(diǎn)。

public void arcTo(RectF oval, float startAngle, float sweepAngle,
                  boolean forceMoveTo) {
    arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo);
}

public void arcTo(RectF oval, float startAngle, float sweepAngle) {
    arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, false);
}

public void arcTo(float left, float top, float right, float bottom, float startAngle,
        float sweepAngle, boolean forceMoveTo) {
    isSimplePath = false;
    nArcTo(mNativePath, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
}

參數(shù):forceMoveTo
true 將最后一個(gè)點(diǎn)移動(dòng)到圓弧起點(diǎn),即不連接最后一個(gè)點(diǎn)與圓弧起點(diǎn),
false 不移動(dòng),而是連接最后一個(gè)點(diǎn)與圓弧起點(diǎn)

示例代碼:

mPath.moveTo(0,0);
mPath.lineTo(100,100);
mPath.arcTo(rectF1,0,270,true);
mPath.moveTo(0,0);
mPath.lineTo(100,100);
mPath.arcTo(rectF1,0,270,false);

5 addCircle 添加圓形路徑:

public void addCircle(float x, float y, float radius, Direction dir) {
    isSimplePath = false;
    nAddCircle(mNativePath, x, y, radius, dir.nativeInt);
}

x,y:圓心坐標(biāo)
Radius:半徑
Direction:方向
Path.Direction:設(shè)置添加path的順序,CW順時(shí)針,CCW逆時(shí)針,在添加圖形時(shí)確定閉合順序(各個(gè)點(diǎn)的記錄順序)

public enum Direction {
    /** clockwise */
    CW  (0),    // must match enum in SkPath.h
    /** counter-clockwise */
    CCW (1);    // must match enum in SkPath.h
}

所以Direction會(huì)改變連接順序,類(lèi)似繪制矩形A-B-C-D ,順時(shí)針繪制順序?yàn)锳-B-C-D,如果設(shè)置了逆時(shí)針就是A-D-C-B。
注意:繪制圓形,矩形最終圖形不受順序影響,按照路徑繪制文字,會(huì)按照Direction方向進(jìn)行繪制。

mPath.addCircle(400,400,300, Path.Direction.CW);

6 addOval 添加橢圓路徑

public void addOval(RectF oval, Direction dir) {
    addOval(oval.left, oval.top, oval.right, oval.bottom, dir);
}

public void addOval(float left, float top, float right, float bottom, Direction dir) {
    isSimplePath = false;
    nAddOval(mNativePath, left, top, right, bottom, dir.nativeInt);
}

  RectF rectF1 = new RectF(200,200,500,600);
  mPath.addOval(rectF1,Path.Direction.CW);

7 addPath 添加Path路徑

//合并path之前做偏移處理
public void addPath(Path src, float dx, float dy) {
    isSimplePath = false;
    nAddPath(mNativePath, src.mNativePath, dx, dy);
}

//合并兩個(gè)Path
public void addPath(Path src) {
    isSimplePath = false;
    nAddPath(mNativePath, src.mNativePath);
}

//添加路徑之前做matrix變換
public void addPath(Path src, Matrix matrix) {
    if (!src.isSimplePath) isSimplePath = false;
    nAddPath(mNativePath, src.mNativePath, matrix.native_instance);
}
  • addPath(Path src, float dx, float dy)進(jìn)行了位移之后再添加進(jìn)當(dāng)前path中。

  • addPath(Path)將兩個(gè)Path合并成為一個(gè)。

  • addPath(Path src, Matrix matrix)添加到當(dāng)前path之前先使用Matrix進(jìn)行變換。

第一種

mPath.moveTo(100,70);
mPath.lineTo(140,180);
mPath.lineTo(250,330);
mPath.lineTo(400,630);
mPath.lineTo(100,830);

Path newPath = new Path();
newPath .moveTo(100,1000);
newPath .lineTo(600,1300);
newPath .lineTo(400,1700);

mPath.addPath(newPath);

第二種

mPath.moveTo(100,70);
mPath.lineTo(140,180);
mPath.lineTo(250,330);
mPath.lineTo(400,630);
mPath.lineTo(100,830);

Path newPath = new Path();
newPath.moveTo(100,1000);
newPath.lineTo(600,1300);
newPath.lineTo(400,1700);

mPath.addPath(newPath,300,100);

生成的圖形向右向下移動(dòng)了。

第三種

mPath.moveTo(100,70);
mPath.lineTo(140,180);
mPath.lineTo(250,330);
mPath.lineTo(400,630);
mPath.lineTo(100,830);

Path newPath = new Path();
newPath.moveTo(100,1000);
newPath.lineTo(600,1300);
newPath.lineTo(400,1700);

Matrix matrix = new Matrix();
matrix.postScale(0.5f,0.5f);
mPath.addPath(newPath,matrix);

8 addRect addRoundRect 添加矩形

public void addRect(RectF rect, Direction dir) {
    addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
}

public void addRect(float left, float top, float right, float bottom, Direction dir) {
    detectSimplePath(left, top, right, bottom, dir);
    nAddRect(mNativePath, left, top, right, bottom, dir.nativeInt);
}
public void addRoundRect(RectF rect, float rx, float ry, Direction dir) {
    addRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, dir);
}

public void addRoundRect(float left, float top, float right, float bottom, float rx, float ry,
        Direction dir) {
    isSimplePath = false;
    nAddRoundRect(mNativePath, left, top, right, bottom, rx, ry, dir.nativeInt);
}

public void addRoundRect(RectF rect, float[] radii, Direction dir) {
    if (rect == null) {
        throw new NullPointerException("need rect parameter");
    }
    addRoundRect(rect.left, rect.top, rect.right, rect.bottom, radii, dir);
}

實(shí)例代碼:

RectF rectF = new RectF(200, 200, 500, 700);
RectF rectF5 = new RectF(200, 800, 700, 1200);
mPath.addRect(rectF, Path.Direction.CCW);
mPath.addRoundRect(rectF5, 20,20,Path.Direction.CCW);

定制四個(gè)角的弧度
addRoundRect(RectF rect, float[] radii, Direction dir)可以定制矩形四個(gè)角的弧度。

float[] radii:需要傳入8個(gè)數(shù)值,分四組,分別對(duì)應(yīng)每個(gè)角所使用的橢圓的橫軸半徑和縱軸半徑,從左上角開(kāi)始。

RectF rectF3 = new RectF(200,200,900,700);
float[] radii = {70, 70, 70, 30, 30, 70, 70, 0};
mPath.addRoundRect(rectF3,radii, Path.Direction.CW);

9 quadTo cubicTo 曲線(xiàn)

quadTo ,cubicTo用來(lái)實(shí)現(xiàn)貝塞爾曲線(xiàn),quadTo有一個(gè)控制點(diǎn),cubicTo有兩個(gè)控制點(diǎn)。
有點(diǎn)難度以后會(huì)開(kāi)文章講解。
mPath.moveTo(300,500);
mPath.quadTo(500,100,800,500);

貝塞爾曲線(xiàn)學(xué)習(xí)和使用

android繪圖之Paint(1)
android繪圖之Canvas基礎(chǔ)(2)
Android繪圖之Path(3)
Android繪圖之drawText繪制文本相關(guān)(4)
Android繪圖之Canvas概念理解(5)
Android繪圖之Canvas變換(6)
Android繪圖之Canvas狀態(tài)保存和恢復(fù)(7)
Android繪圖之PathEffect (8)
Android繪圖之LinearGradient線(xiàn)性漸變(9)
Android繪圖之SweepGradient(10)
Android繪圖之RadialGradient 放射漸變(11)
Android繪制之BitmapShader(12)
Android繪圖之ComposeShader,PorterDuff.mode及Xfermode(13)
Android繪圖之drawText,getTextBounds,measureText,FontMetrics,基線(xiàn)(14)
Android繪圖之貝塞爾曲線(xiàn)簡(jiǎn)介(15)
Android繪圖之PathMeasure(16)
Android 動(dòng)態(tài)修改漸變 GradientDrawable

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容