Android知識總結——Path經常使用方法解析

版權聲明:本文爲博主原創文章,未經博主容許不得轉載html

Github:github.com/AnliaLeejava

你們要是看到有錯誤的地方或者有啥好的建議,歡迎留言評論android

前言:開發過程當中很容易忘記一些API的使用方法,網上搜索或者在源碼裏找也很難短期內篩選出本身須要的,遂本身將這些知識總結一番git


1、xxxTo方法

Path類中提供了一套xxxTo方法,其做用是從起點到終點移動path畫筆並繪製線(moveTo方法只移動path畫筆不繪製線),線有直線和曲線。方法彙總以下表所示github

方法名 參數解析
lineTo(float x, float y) 繪製直線x:終點x座標值,y:終點y座標值
moveTo(float x, float y) 移動畫筆x:終點x座標值,y:終點y座標值
arcTo(RectF oval, float startAngle, float sweepAngle) 繪製圓弧oval:圓弧矩形區域,startAngle:起始角度,sweepAngle:圓弧旋轉的角度
arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo) 繪製圓弧oval:圓弧矩形區域,startAngle:起始角度,sweepAngle:圓弧旋轉的角度,forceMoveTo:是否在繪製圓弧前移動(moveTo)path畫筆位置
arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo) 繪製圓弧left、top、right、bottom組成圓弧矩形區域,startAngle:起始角度,sweepAngle:圓弧旋轉的角度,forceMoveTo:是否在繪製圓弧前移動(moveTo)path畫筆位置
quadTo(float x1, float y1, float x2, float y2) 繪製二階貝塞爾曲線控制點座標:(x1,y1)終點座標:(x2,y2)
cubicTo(float x1, float y1, float x2, float y2,float x3, float y3) 繪製三階貝塞爾曲線,其中控制點1座標爲 (x1,y1)控制點2座標爲(x2,y2),終點座標爲(x3,y3)

1.lineTo(float x, float y)

繪製直線,從當前畫筆位置出發,鏈接終點(x,y),示例以下canvas

示例以下數組

path.lineTo(300,300);
canvas.drawPath(path,paint);
複製代碼


2.moveTo(float x, float y)

移動畫筆,從當前畫筆位置移動到終點(x,y)數據結構

示例以下post

path.moveTo(100,100);
path.lineTo(300,300);
canvas.drawPath(path,paint);
複製代碼


3.arcTo(RectF oval, float startAngle, float sweepAngle)

繪製圓弧,從當前畫筆位置出發,連線到內切矩形區域oval的圓弧的起始角度startAngle位置(X軸正方向爲0°),順時針旋轉繪製圓弧,旋轉度數爲sweepAngle(sweepAngle爲負時則逆時針旋轉)動畫

示例以下

RectF rectF = new RectF(100,100,300,400);
path.arcTo(rectF,0,180);
canvas.drawPath(path,pathPaint);
複製代碼

arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)

繪製圓弧,若forceMoveTofalse,則用法和arcTo(RectF oval, float startAngle, float sweepAngle)同樣,繪製圓弧以前不會移動(moveTo)path畫筆位置。若爲true,先強制調用moveTo移動path畫筆至圓弧起點,再繪製圓弧。ps:若是調用arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)方法以前沒有對path進行任何操做,則forceMoveTo設置truefalse效果都和設置true同樣

示例以下,注意對比之間的差別

RectF rectF = new RectF(100,100,300,400);
path.moveTo(100,100);
path.arcTo(rectF,0,180,false);
path.close();
canvas.drawPath(path,pathPaint);
複製代碼

RectF rectF = new RectF(100,100,300,400);
path.moveTo(100,100);
path.arcTo(rectF,0,180,true);
path.close();
canvas.drawPath(path,pathPaint);
複製代碼

RectF rectF = new RectF(100,100,300,400);
path.arcTo(rectF,0,180,false);
path.close();
canvas.drawPath(path,pathPaint);
複製代碼

arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)

arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)用法同樣


4.quadTo(float x1, float y1, float x2, float y2)

從path畫筆當前位置出發,以(x₁,y₁)爲控制點,向終點(x₂,y₂)繪製一條二階貝塞爾曲線

示例以下

path.moveTo(100,100);
path.quadTo(200,0,400,100);
canvas.drawPath(path,pathPaint);
複製代碼


5.cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

從path畫筆當前位置出發,以(x1,y1)爲控制點1以(x2,y2)爲控制點2,向終點(x3,y3)繪製一條三階貝塞爾曲線

簡單示例以下

path.moveTo(100,100);
path.cubicTo(200,0,300,90,500,100);
canvas.drawPath(path,pathPaint);
複製代碼

圓形其實也是由四段三階貝塞爾曲線組成,咱們繪製其中兩段看看效果便可,示例以下

path.moveTo(300,200);
path.cubicTo(300,200+100*0.551915024494f,200+100*0.551915024494f,300,200,300);

path.moveTo(200-20,300);
path.cubicTo(200-100*0.551915024494f-20,300,100-20,200+100*0.551915024494f,100-20,200);
canvas.drawPath(path,pathPaint);
複製代碼


2、rXxxTo方法

rXxxTo方法r意思是relative,即相對的意思,方法有四個,如上圖所示,其功能與對應的xxxTo方法同樣,區別在於rXxxTo方法在繪製Path時是以當前path畫筆位置爲座標原點,即相對於path畫筆位置進行繪製,而xxxTo方法的座標原點則與當前canvas座標原點一致。例如,咱們使用xxxTo方法

path.moveTo(100,100);
path.lineTo(300,300);
canvas.drawPath(path, pathPaint);
複製代碼

上述代碼是從(100,100)到(300,300)繪製一條直線,那麼若是用rXxxTo方法,相對(100,100)這個點繪製直線,則終點應爲(300-100,300-100),即終點設爲(200,200),以下所示

path.moveTo(100,100);
path.rLineTo(200,200);
canvas.drawPath(path, pathPaint);
複製代碼

效果都是同樣的


3、addXxx方法

Path類中還提供了一套addXxx方法,字面理解就是添加一段相應的線,線能夠是曲線、完整的圓形、矩形等,甚至能夠是另外一組Path的線。所謂添加的意思,我我的理解就是在繪製這段線前移動(moveTo)path畫筆位置到線的起始位置,而後再繪製線,也就是說添加的這段線,與以前繪製的Path是分離的(除非後繪製的這段線的起始點與以前Path的終點一致)。方法彙總以下表所示

方法名 參數解析
addArc(RectF oval, float startAngle, float sweepAngle) 添加圓弧oval:圓弧矩形區域,startAngle:起始角度,sweepAngle:圓弧旋轉的角度
addArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle) 添加圓弧left、top、right、bottom組成圓弧矩形區域,startAngle:起始角度,sweepAngle:圓弧旋轉的角度。ps:此方法在API 19以上有效
addCircle(float x, float y, float radius, Direction dir) 添加圓形x:圓形圓心的x座標,y:圓形圓心的y座標,radius:圓形半徑,dir:線的閉合方向(CW順時針方向 | CCW逆時針方向)
addOval(RectF oval, Direction dir) 添加橢圓oval:橢圓內切的矩形區域,dir:線的閉合方向(CW順時針方向 | CCW逆時針方向)
addOval(float left, float top, float right, float bottom, Direction dir) 添加橢圓left、top、right、bottom組成橢圓內切的矩形區域,dir:線的閉合方向(CW順時針方向 | CCW逆時針方向)
addRect(RectF rect, Direction dir) 添加矩形rect:矩形區域,dir:線的閉合方向(CW順時針方向 | CCW逆時針方向)
addRect(float left, float top, float right, float bottom, Direction dir) 添加矩形left、top、right、bottom組成矩形區域,dir:線的閉合方向(CW順時針方向 | CCW逆時針方向)
addRoundRect(RectF rect, float rx, float ry, Direction dir) 添加統一圓角的圓角矩形rect:矩形區域,rx:橢圓圓角的橫軸半徑,ry:橢圓圓角的縱軸半徑,dir:線的閉合方向(CW順時針方向 | CCW逆時針方向)
addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir) 添加統一圓角的圓角矩形left、top、right、bottom組成矩形區域,rx:橢圓圓角的橫軸半徑,ry:橢圓圓角的縱軸半徑,dir:線的閉合方向(CW順時針方向 | CCW逆時針方向)
addRoundRect(RectF rect, float[] radii, Direction dir) 添加非統一圓角的圓角矩形rect:矩形區域,radii:矩形四個橢圓圓角的橫軸半徑和縱軸半徑的數組,一共8個數值,dir:線的閉合方向(CW順時針方向 | CCW逆時針方向)
addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir) 添加非統一圓角的圓角矩形left、top、right、bottom組成矩形區域,radii:矩形四個橢圓圓角的橫軸半徑和縱軸半徑的數組,一共8個數值,dir:線的閉合方向(CW順時針方向 | CCW逆時針方向)
addPath(Path src) 添加一組Pathsrc:要添加的Path
addPath(Path src, float dx, float dy) 添加一組平移後的Pathsrc:要添加的Path,dx:平移的x座標,dy:平移的y座標
addPath(Path src, Matrix matrix) 添加一組通過矩陣變換後的Pathsrc:要添加的Path,matrix:3x3的矩陣

1.addArc(RectF oval, float startAngle, float sweepAngle)

addArc兩個方法使用起來與arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)forceMoveTo設置爲true效果一致,就不展開贅述了


2.addCircle(float x, float y, float radius, Direction dir)

以點(x,y)爲圓心,添加一個半徑長爲radius圓形,繪製起始角度爲0°(x軸方向),繪製方向經過dir的值而定,dirCW時順時針繪製,dirCCW時逆時針繪製

方法比較簡單,主要是對比CWCCW的區別,咱們用canvas.drawTextOnPath方法突顯順時針逆時針繪製的效果,示例以下

path.addCircle(200,150,100, Path.Direction.CW);//順時針繪製
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("繪製順序", path, 0, 0, paint);
複製代碼

path.addCircle(200,150,100, Path.Direction.CCW);//逆時針繪製
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("繪製順序", path, 0, 0, paint);
複製代碼


3.addOval(RectF oval, Direction dir)

oval矩形區域中,添加一個內切的橢圓,繪製起始角度爲0°(x軸方向),繪製方向經過dir的值而定,dirCW時順時針繪製,dirCCW時逆時針繪製

addOval(RectF oval, Direction dir)和addOval(float left, float top, float right, float bottom, Direction dir)效果是同樣的,就不分開講了

RectF rectF = new RectF(100,100,400,250);
path.addOval(rectF, Path.Direction.CW);
canvas.drawPath(path,pathPaint);
複製代碼

效果如圖


4.addRect(RectF rect, Direction dir)

添加一個區域爲rect矩形,繪製起點爲左上角,繪製方向經過dir的值而定,dirCW時順時針繪製,dirCCW時逆時針繪製

addRect(RectF rect, Direction dir)和addRect(float left, float top, float right, float bottom, Direction dir)效果是同樣的,就不分開講了

RectF rectF = new RectF(100,100,400,250);
path.addRect(rectF, Path.Direction.CW);
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("繪製順序", path, 0, 0, paint);
複製代碼

效果如圖


5.addRoundRect(RectF rect, float rx, float ry, Direction dir)

添加一個區域爲rect圓角矩形,四個角的圓角大小一致,圓角的橫軸半徑爲rx縱軸半徑爲rydirCW時順時針繪製,繪製起點爲左下角dirCCW時逆時針繪製,繪製起點爲左上角(注意對比順時針和逆時針的繪製起點

addRoundRect(RectF rect, float rx, float ry, Direction dir)和addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir)效果是同樣的,就不分開講了

RectF rectF = new RectF(100,100,400,350);
path.addRoundRect(rectF,60,30,Path.Direction.CW);//順時針
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("繪製順序", path, 0, 0, paint);
複製代碼

RectF rectF = new RectF(100,100,400,350);
path.addRoundRect(rectF,60,30,Path.Direction.CCW);//逆時針
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("繪製順序", path, 0, 0, paint);
複製代碼

addRoundRect(RectF rect, float[] radii, Direction dir)

添加一個區域爲rect圓角矩形,四個角的圓角的橫軸和縱軸半徑由radii數組中的8個數值決定dirCW時順時針繪製,繪製起點爲左下角dirCCW時逆時針繪製,繪製起點爲左上角(注意對比順時針和逆時針的繪製起點

須要注意的是,若是radii數組中的元素小於8,系統會拋出錯誤信息radii[] needs 8 values,以下圖所示

addRoundRect(RectF rect, float[] radii, Direction dir)和addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)效果是同樣的,就不分開講了

RectF rectF = new RectF(100,100,400,350);
float[] radii = {60,30,30,70,100,100,10,40};
path.addRoundRect(rectF,radii,Path.Direction.CW);
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("繪製順序", path, 0, 0, paint);
複製代碼


6.addPath(Path src)

添加一組名爲srcPath副本

Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.quadTo(200,100,350,200);
copyPath.lineTo(100,250);
copyPath.close();
path.addPath(copyPath);
canvas.drawPath(path,pathPaint);
複製代碼

addPath(Path src, float dx, float dy)

添加一組名爲srcPath副本,而後將其進行平移x軸上的平移距離爲dxy軸上的平移距離爲dy

Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.quadTo(200,100,350,200);
copyPath.lineTo(100,250);
copyPath.close();
path.addPath(copyPath,300,0);//向x軸正方向平移300像素距離
canvas.drawPath(path,pathPaint);
複製代碼

addPath(Path src, Matrix matrix)

添加一組名爲srcPath副本,而後將其進行矩陣變換,矩陣爲matrix(3x3的矩陣)

Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.quadTo(200,100,350,200);
copyPath.lineTo(100,250);
copyPath.close();

Matrix mMatrix = new Matrix();
mMatrix.setScale(1,-1);//以x軸爲中線進行翻轉
mMatrix.postRotate(90);//以座標軸原點爲中心點順時針旋轉90°

path.addPath(copyPath,mMatrix);
canvas.drawPath(path,pathPaint);
複製代碼


4、填充模式

方法名 參數解析
setFillType(FillType ft) 設置Path的填充模式ft:填充類型,有EVEN_ODDINVERSE_EVEN_ODDWINDINGINVERSE_WINDING 四種模式
getFillType() 獲取當前Path的填充模式
isInverseFillType() 判斷當前Path填充模式是不是反向規則(INVERSE_XXX)
toggleInverseFillType() 當前Path的填充模式與其反向規則模式進行相互切換

填充模式要解釋起來仍是挺費口舌的,這裏就把前輩們的博客貼出來,他們解釋得都很是清楚,我就很少贅述了


5、其餘方法

方法名 參數解析
close() 封閉當前Path,鏈接起點終點
reset() 清空Path中的全部直線和曲線,保留填充模式設置,不保留Path上相關的數據結構
rewind() 清空Path中的全部直線和曲線,不保留填充模式設置,但會保留Path上相關的數據結構,以便高效地複用
set(Path src) 用名爲src的Path替換當前的Path
op(Path path, Op op) 當前Path名爲path的Path進行布爾運算(取差集、交集、並集等)op:運算邏輯,有DIFFERENCE(差集)REVERSE_DIFFERENCE(差集)INTERSECT(交集)UNION(並集)XOR(異或)五種運算邏輯可選。ps:此方法在API 19以上有效
offset(float dx, float dy) 平移當前Pathx軸上平移的距離爲dxy軸上平移的距離爲dy
offset(float dx, float dy, Path dst) 平移名爲dst的Pathx軸上平移的距離爲dxy軸上平移的距離爲dy
transform(Matrix matrix) 對當前Path進行矩陣變換,矩陣爲matrix(3x3矩陣)
transform(Matrix matrix, Path dst) 對名爲dst的Path進行矩陣變換,矩陣爲matrix(3x3矩陣)
setLastPoint(float dx, float dy) 設置終點,設置當前Path最後一個點的位置爲(dx,dy)
isEmpty() 判斷當前Path是否爲空
isConvex() 判斷當前Path圍成的圖形是否凸多邊形。ps:此方法在API 21以上有效
isRect(RectF rect) 判斷當前Path是否爲矩形,如是,則將當前Path存儲到新建的rect中

這裏大多數方法都比較簡單,有些以前已經應用過,就不展開來說了,下面介紹一下其中比較特別且經常使用的幾個方法

1.op(Path path, Op op) 布爾運算

前面的表格咱們提到參數op共有五種運算邏輯可選,下面咱們就來看看這五種運算邏輯是如何影響兩個Path之間的關係的,咱們先用不一樣的顏色繪製出一個矩形和一個圓形,觀察一下它們的位置和關係

Path path1 = new Path();
path1.addRect(100,100,300,300, Path.Direction.CW);
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path1,pathPaint);

Path path2 = new Path();
path2.addCircle(300,250,100,Path.Direction.CW);
pathPaint.setColor(Color.RED);
canvas.drawPath(path2,pathPaint);
複製代碼

下面咱們對這兩個Path進行布爾運算

DIFFERENCE(差集)

若op方法的調用關係爲path1.op(path2, Path.Op.DIFFERENCE),則運算結果是path1減去與path2的交集後剩下的部分,即path1與path2的並集減去path2部分

Path path1 = new Path();
path1.addRect(100,100,300,300, Path.Direction.CW);

Path path2 = new Path();
path2.addCircle(300,250,100,Path.Direction.CW);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	path1.op(path2, Path.Op.DIFFERENCE);//path1與path2進行布爾運算,結果保存至path1
	canvas.drawPath(path1,pathPaint);
}

//也能夠這樣寫
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	path3.op(path1,path2,Path.Op.DIFFERENCE);//path1與path2進行布爾運算,結果保存至path3
	canvas.drawPath(path3,pathPaint);
}
複製代碼

能夠用path1.op直接運算,也能夠新建一個path3保存path1和path2的運算結果,效果都是同樣的

REVERSE_DIFFERENCE(差集)

若op方法的調用關係爲path1.op(path2, Path.Op.REVERSE_DIFFERENCE),則運算結果是path2減去與path1的交集後剩下的部分,即path1與path2的並集減去path1部分

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	path1.op(path2, Path.Op.REVERSE_DIFFERENCE);//path1與path2進行布爾運算,結果保存至path1
	canvas.drawPath(path1,pathPaint);
}

//也能夠這樣寫
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	path3.op(path1,path2,Path.Op.REVERSE_DIFFERENCE);//path1與path2進行布爾運算,結果保存至path3
	canvas.drawPath(path3,pathPaint);
}
複製代碼

INTERSECT(交集)

若op方法的調用關係爲path1.op(path2, Path.Op.INTERSECT),則運算結果是path1與path2的交集

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	path1.op(path2, Path.Op.INTERSECT);//path1與path2進行布爾運算,結果保存至path1
	canvas.drawPath(path1,pathPaint);
}

//也能夠這樣寫
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	path3.op(path1,path2,Path.Op.INTERSECT);//path1與path2進行布爾運算,結果保存至path3
	canvas.drawPath(path3,pathPaint);
}
複製代碼

UNION(並集)

若op方法的調用關係爲path1.op(path2, Path.Op.UNION),則運算結果是path1與path2的並集

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	path1.op(path2, Path.Op.UNION);//path1與path2進行布爾運算,結果保存至path1
	canvas.drawPath(path1,pathPaint);
}

//也能夠這樣寫
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	path3.op(path1,path2,Path.Op.UNION);//path1與path2進行布爾運算,結果保存至path3
	canvas.drawPath(path3,pathPaint);
}
複製代碼

XOR(異或)

若op方法的調用關係爲path1.op(path2, Path.Op.XOR),則運算結果是path1與path2的並集減去path1與path2的交集

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	path1.op(path2, Path.Op.XOR);//path1與path2進行布爾運算,結果保存至path1
	canvas.drawPath(path1,pathPaint);
}

//也能夠這樣寫
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	path3.op(path1,path2,Path.Op.XOR);//path1與path2進行布爾運算,結果保存至path3
	canvas.drawPath(path3,pathPaint);
}
複製代碼


2.setLastPoint(float dx, float dy)

Path在調用setLastPoint方法以前執行了某項操做時(繪製直線或曲線等),會將該操做的終點強制設置爲(dx,dy)連線(線的曲直取決於該操做自己是繪製直線仍是曲線)

理解這個方法以前,首先咱們要知道不管是使用addXxx方法仍是xxxTo方法等在繪製過程當中其實都是根據一堆點的集合,按順序連線(直線或曲線)後繪製出Path最終的樣子setLastPoint方法正是改變此方法調用以前點的集合中最後一個點的位置。下面咱們經過**封閉圖形(矩形)非封閉圖形(一段圓弧)**的例子更好地理解這個方法

//用綠線繪製一個矩形
path.addRect(new RectF(100,100,300,300), Path.Direction.CW);
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path,pathPaint);

//強制設置最後一個點爲(150,250),用紅線繪製觀察變化
path.reset();
path.addRect(new RectF(100,100,300,300), Path.Direction.CW);
path.setLastPoint(150,250);
pathPaint.setColor(Color.RED);
canvas.drawPath(path,pathPaint);
複製代碼

//用綠線繪製一個旋轉180°的圓弧
path.addArc(new RectF(100,100,300,300),0,180);
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path,pathPaint);

//強制設置最後一個點爲(200,200),用紅線繪製觀察變化
path.reset();
path.addArc(new RectF(100,100,300,300),0,180);
path.setLastPoint(200,200);
pathPaint.setColor(Color.RED);
canvas.drawPath(path,pathPaint);
複製代碼

至此本篇總結到此結束,如有什麼遺漏和錯誤的地方歡迎留言指出,若是你們看了感受還不錯麻煩點個贊,大家的支持是我最大的動力~
相關文章
相關標籤/搜索