Path是一個(gè)類,表示“路徑”.
路徑:就是無數(shù)個(gè)點(diǎn)連接起來形成的軌跡,這個(gè)路徑中還包括起點(diǎn)信息薇搁、終點(diǎn)信息,方向信息
Canvas中繪制路徑Path的方法:
public void drawPath(Path path, Paint paint)
一渡八、Path方法大全
這里先給出Path中常用方法啃洋,現(xiàn)在看不懂沒關(guān)系,在后面都會(huì)一一介紹到
1屎鳍、移動(dòng)起點(diǎn)
moveTo宏娄、rMoveTo 移動(dòng)畫筆下一次操作的起點(diǎn)
2、設(shè)置終點(diǎn)
setLastPoint 重置當(dāng)前Path中最后一個(gè)點(diǎn)位置逮壁,會(huì)影響之前的繪制效果
3孵坚、兩點(diǎn)之間連接成一條線段
lineTo、rLineTo 將兩點(diǎn)之間連接成一條線段
close 將最開始操作點(diǎn)貌踏、最后操作點(diǎn)連接起來十饥,形成閉合路徑
4、添加基本圖形的路徑
addRect祖乳、addRoundRect添加直角逗堵、圓角矩形
addOval、addCircle眷昆、addArc蜒秤、arcTo添加橢圓、圓亚斋、弧1作媚、弧2
5、判斷
isEmpty 判斷Path是否為空
isRect 判斷path是否是一個(gè)矩形
6帅刊、設(shè)置路徑纸泡,偏移路徑,添加路徑
set 為當(dāng)前Path設(shè)置路徑
offset 對(duì)當(dāng)前路徑進(jìn)行偏移(不會(huì)影響之后的操作)
addPath 為當(dāng)前Path添加路徑
7赖瞒、填充模式
setFillType 設(shè)置填充模式
getFillType 獲取當(dāng)前填充模式
isInverseFillType 判斷是否是反向填充模式
toggleInverseFillType 原有規(guī)則與反向規(guī)則之間相互切換
8女揭、重置
reset 保留填充模式重置path
rewind 保留數(shù)據(jù)結(jié)構(gòu)重置path
9、貝塞爾曲線
quadTo栏饮、rQuadTo 二階貝賽爾曲線
cubicTo吧兔、rCubicTo 三階貝塞爾曲線
10、兩個(gè)Path運(yùn)算(差集袍嬉、反差集境蔼、交集灶平、并集、補(bǔ)集)
op 兩個(gè)Path進(jìn)行運(yùn)算
11箍土、計(jì)算邊界
computeBounds 計(jì)算Path的邊界信息保存在矩形RectF對(duì)象中
12逢享、矩陣操作
transform
二、Path基礎(chǔ)
1涮帘、移動(dòng)起點(diǎn)
現(xiàn)實(shí)中畫畫肯定有個(gè)起始點(diǎn)拼苍,Path添加路徑也有個(gè)起始點(diǎn)
public void moveTo(float x, float y)
絕對(duì)定位------將畫筆移動(dòng)到點(diǎn)(x,y)
public void rMoveTo(float dx, float dy)
r:relative
相對(duì)定位------將畫筆移動(dòng)到點(diǎn)(x+dx调缨,y+dy)疮鲫,(x,y)是上一次的點(diǎn)
現(xiàn)實(shí)中作畫時(shí)肯定有個(gè)開始點(diǎn)弦叶,這兩個(gè)方法就是Path中確定開始點(diǎn)的
默認(rèn)開始點(diǎn)(0俊犯,0)
現(xiàn)實(shí)中作畫時(shí)肯定會(huì)收筆,就會(huì)出現(xiàn)一個(gè)終點(diǎn)伤哺,在Path中每次添加完路徑后的終點(diǎn)就是下一次添加路徑的起始點(diǎn)
2燕侠、開放路徑、閉合路徑
從起點(diǎn)開始在路徑中添加線段立莉,一直到終點(diǎn)停止绢彤,此時(shí)就形成了一個(gè)開放路徑,若把終點(diǎn)和起點(diǎn)連接起來(閉合),或者線段最后的終點(diǎn)和起點(diǎn)重合,就會(huì)形成一個(gè)閉合路徑.
3翩剪、判斷一個(gè)點(diǎn)在圖形內(nèi)還是圖形外
(1)奇偶規(guī)則
從點(diǎn)P任意方向作射線,若射線與圖形交點(diǎn)為奇數(shù)饶氏,則點(diǎn)P在圖形內(nèi),交點(diǎn)為偶數(shù)表示點(diǎn)P在圖形外
P1有勾、P2作出的射線與圖形的交點(diǎn)分別為0疹启、2,偶數(shù)蔼卡,故在圖形外部
P3作出的射線與圖形的交點(diǎn)分別為1喊崖,奇數(shù),故在圖形內(nèi)部
(2)非零環(huán)繞數(shù)規(guī)則
首先將多邊形的邊矢量化雇逞,從點(diǎn)P任意方向作射線荤懂,每當(dāng)圖形的邊從射線右側(cè)穿到射線左側(cè)時(shí),環(huán)繞數(shù)+1喝峦,從左到右穿過時(shí)势誊,環(huán)繞數(shù)-1呜达。最終環(huán)繞數(shù)和為非零谣蠢,則點(diǎn)P為內(nèi)部點(diǎn),否則,點(diǎn)P是外部點(diǎn)
P1:不相交眉踱,所以環(huán)繞數(shù)為0挤忙,在圖形外部
P2:矩形底邊從射線右側(cè)穿到射線左側(cè),環(huán)繞數(shù)+1谈喳,矩形右邊從從射線左側(cè)穿到射線右側(cè)册烈,環(huán)繞數(shù)-1,最終環(huán)繞數(shù)和為0婿禽,在圖形內(nèi)部
P3:矩形底邊從射線右側(cè)穿到射線左側(cè)赏僧,環(huán)繞數(shù)+1,在圖形內(nèi)部
PS:這里的圖形指的是封閉路徑扭倾,通常情況下這兩種判斷方法結(jié)果是一樣的淀零,但是也會(huì)出現(xiàn)不一樣的情況,在下面填充模式會(huì)介紹到
三膛壹、Path中添加線段
Path類可以添加各種形狀的線條驾中,并且能將線條組合在一起,閉合之后就成是一個(gè)多邊形.
public void lineTo(float x, float y)
(x模聋,y):直線的結(jié)束點(diǎn)肩民,又是下一次繪制直線路徑的開始點(diǎn)
在上一個(gè)點(diǎn)與當(dāng)前新點(diǎn)(x,y)之間畫一條線
(如果沒有定義過初始點(diǎn)并且沒有上一次操作链方,起始點(diǎn)就是坐標(biāo)原點(diǎn)(0,0))
public void rLineTo(float dx, float dy)
(dx+x持痰,dy+y):直線的結(jié)束點(diǎn),又是下一次繪制直線路徑的開始點(diǎn)
在上一個(gè)點(diǎn)與當(dāng)前新點(diǎn)(dx+x侄柔,dy+y)之間畫一條線
public void close()
在第一個(gè)點(diǎn)和最后一個(gè)點(diǎn)之間畫一條線共啃,形成閉合圖形
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
Path path = new Path();
path.moveTo(50, 50);//起點(diǎn):(50,50)
path.lineTo(250, 50);//(50,50)到(250,50)之間畫一條線,(250,50)是下一次繪制的起點(diǎn)
path.lineTo(250, 250);//(250,50)到(250,250)之間畫一條線
path.close();//閉合
canvas.drawPath(path, mPaint);
mPaint.setColor(Color.RED);
Path path2 = new Path();
path2.moveTo(300, 50);//起點(diǎn):(300,50)
path2.lineTo(500, 50);//(300,50)到(500,50)之間畫一條線暂题,(500,50)是下一次繪制的起點(diǎn)
path2.rMoveTo(-200, 0);//將起點(diǎn)移動(dòng)到(500-200,50+0)---(300,,50)成為下一次繪制的起點(diǎn)
path2.rLineTo(0, 200);//(300,50)到(300+0,50+200)之間畫一條線
canvas.drawPath(path2, mPaint);
}
四移剪、setLastPoint
Path中還有一個(gè)移動(dòng)操作點(diǎn)位置的方法,和moveTo有區(qū)別:
public void setLastPoint(float dx, float dy)
設(shè)置Path之前操作的最后一個(gè)點(diǎn)位置
拿上面藍(lán)色三角形舉例:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
Path path = new Path();
path.moveTo(50, 50);
path.lineTo(250, 50);
path.lineTo(250, 250);
path.setLastPoint(250,100);//將最后一個(gè)點(diǎn)位置設(shè)置為(250,100)
path.close();
canvas.drawPath(path, mPaint);
}
僅僅多加了一行代碼:本來閉合前最后一個(gè)點(diǎn)應(yīng)該是(250, 250)薪者,現(xiàn)在變成了(250,100)纵苛,所以閉合時(shí)連接的是(250,100)和最初的起點(diǎn)(50, 50).
可見:setLastPoint會(huì)影響之前的繪圖,還會(huì)把之后的繪圖起點(diǎn)更改
而moveTo僅僅影響之后的繪圖言津,對(duì)之前的繪圖沒有影響.
五攻人、Path中添加矩形
往Path中添加矩形、橢圓悬槽、圓怀吻、弧,需要調(diào)用Path類中以“add”開頭的相關(guān)方法.
關(guān)于矩形初婆,請(qǐng)看Rect類蓬坡、RectF類猿棉,Canvas中繪制矩形相關(guān)介紹.
1、直角矩形
public void addRect(RectF rect, Direction dir)
public void addRect(float left, float top, float right, float bottom, Direction dir)
往Path中添加一個(gè)直角矩形
Direction:Path類中枚舉類屑咳,表示Path繪制的方向萨赁,可選值:
Path.Direction.CW 順時(shí)針
Path.Direction.CCW 逆時(shí)針
方向:
path.addRect(100,100,300,200, Path.Direction.CW);//矩形ABCD
path.addRect(100,100,300,200, Path.Direction.CCW);//矩形ADCB
2、圓角矩形
public void addRoundRect(RectF rect, float rx, float ry, Direction dir)
public void addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir)
往Path中添加一個(gè)圓角矩形(4個(gè)圓角一樣)
public void addRoundRect(RectF rect, float[] radii, Direction dir)
public void addRoundRect(float left, float top, float right, float bottom, float[] radii, Direction dir)
往Path中添加一個(gè)圓角矩形(4個(gè)圓角可定制)
這里的參數(shù)除了radii兆龙,之前的文章都介紹過
radii:定義4個(gè)圓角的數(shù)組杖爽,一個(gè)圓角需要2個(gè)值,總共需要8個(gè)值:
順序:左上角紫皇,右上角慰安,右下角,左下角
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
Path path = new Path();
RectF rectF = new RectF(50, 50, 600, 400);
path.addRect(rectF, Path.Direction.CW);
RectF rectF2 = new RectF(100, 100, 500, 300);
path.addRoundRect(rectF2, new float[]{10, 10, 20, 20, 0, 0, 40, 40}, Path.Direction.CW);
canvas.drawPath(path, mPaint);
}
六聪铺、添加橢圓泻帮、圓、弧
關(guān)于圓计寇,下面這些橢圓锣杂、圓、弧的方法參數(shù)和Canvas類中繪制圓作用一樣番宁,這里就不介紹了.
1元莫、橢圓
public void addOval(RectF oval, Direction dir)
public void addOval(float left, float top, float right, float bottom, Direction dir)
2、圓
public void addCircle(float x, float y, float radius, Direction dir)
3踱蠢、弧1
public void addArc(RectF oval, float startAngle, float sweepAngle)
public void addArc(float left, float top, float right, float bottom, float startAngle,
float sweepAngle)
4、弧2
public void arcTo(RectF oval, float startAngle, float sweepAngle)
public void arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)
public void arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)
這里多了一個(gè)參數(shù)沒有介紹過:forceMoveTo
forceMoveTo表示是否強(qiáng)制開始一個(gè)新的起點(diǎn)棋电,默認(rèn)false茎截,會(huì)在繪制弧的時(shí)候把弧的起點(diǎn)和Path上一次終點(diǎn)連接起來
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
Path path = new Path();
path.addOval(new RectF(50, 50, 600, 400), Path.Direction.CW);//順時(shí)針橢圓
path.addCircle(150, 550, 100, Path.Direction.CW);//順時(shí)針圓
path.addArc(new RectF(80, 80, 630, 430), 0, 90);//弧1
path.arcTo(new RectF(100, 100, 660, 460), 0, 90, false);//弧2
canvas.drawPath(path, mPaint);
}
七、判斷
public boolean isEmpty()
判斷路徑是否為空赶盔,為空企锌,返回true(Path中未添加任何線段或者曲線)
public boolean isRect(RectF rect)
判斷路徑是否為矩形,如果是于未,返回true撕攒,將矩形的信息存放進(jìn)參數(shù)rect中,否則返回false烘浦,忽略rect
這兩個(gè)方法很簡單抖坪,就不再測試了
八、設(shè)置路徑闷叉,偏移路徑擦俐,添加路徑
1、設(shè)置路徑
public void set(Path src)
將傳入的Path路徑src設(shè)置給當(dāng)前的Path對(duì)象
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
Path path1 = new Path();
Path path2 = new Path();
path1.lineTo(200, 200);
// path2.set(path1);設(shè)置路徑
canvas.drawPath(path2, mPaint);
}
上面的測試代碼運(yùn)行界面上將沒有任何效果握侧,因?yàn)閜ath2中未添加任何內(nèi)容蚯瞧,但是放開注釋蹬叭,為path2設(shè)置路徑后將會(huì)出現(xiàn)一條從(0,0)到(200状知,200)的線段.
2、偏移路徑
public void offset(float dx, float dy)
對(duì)當(dāng)前路徑進(jìn)行偏移孽查,dx饥悴、dy分別是Path水平、豎直方向的平移距離(不會(huì)影響之后的操作)
接著上面測試代碼新加一行:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
Path path1 = new Path();
Path path2 = new Path();
path1.lineTo(200, 200);
path2.set(path1);//設(shè)置路徑
path2.offset(300, 100);//偏移路徑
canvas.drawPath(path2, mPaint);
}
3盲再、添加路徑
public void addPath(Path src)
將src的路徑添加到當(dāng)前Path對(duì)象中
public void addPath(Path src, float dx, float dy)
將src的路徑水平西设、豎直方向分別偏移dx、dy距離后添加到當(dāng)前Path對(duì)象中
繼續(xù)上面的測試:
private void gogogo1(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
Path path1 = new Path();
Path path2 = new Path();
path1.lineTo(200, 200);
path2.set(path1);//設(shè)置路徑
path2.offset(300, 100);//偏移路徑
path2.addPath(path1);//添加路徑
path2.addPath(path1, 200, 100);//添加路徑
canvas.drawPath(path2, mPaint);
}
九答朋、填充模式
public void setFillType(FillType ft)
設(shè)置填充模式
FillType 可選值:
Path.FillType.WINDING 非零環(huán)繞數(shù)規(guī)則(默認(rèn)填充模式)
Path.FillType.INVERSE_WINDING 反非零環(huán)繞數(shù)規(guī)則
Path.FillType.EVEN_ODD 奇偶規(guī)則
Path.FillType.INVERSE_EVEN_ODD 反奇偶規(guī)則
填充:將圖形內(nèi)部填滿某種顏色
Path代表路徑贷揽,本文一開始介紹了如何判斷一個(gè)點(diǎn)在圖形的內(nèi)部還是外部,而填充就是將Path形成的圖形內(nèi)部所有點(diǎn)都填滿某種顏色梦碗,幾乎所有繪圖軟件中都有填充功能禽绪,下面以電腦上的畫圖軟件示例:
注意:填充針對(duì)的是圖形內(nèi)部
1、填充模式分為兩組
根據(jù)奇偶規(guī)則判斷的填充模式洪规、根據(jù)非零環(huán)繞數(shù)規(guī)則判斷的填充模式.
每組的兩個(gè)模式填充效果相反.
2印屁、為什么會(huì)分為兩組
這是因?yàn)樵谀承┣闆r下這兩組判斷的結(jié)果不一樣.
對(duì)于簡單的封閉路徑(路徑無相交的現(xiàn)象),圖形的外部和內(nèi)部和很容易判斷.
但對(duì)于一些復(fù)雜的封閉路徑斩例,圖形的外部和內(nèi)部根據(jù)不同模式判斷結(jié)果不一樣.
(如下圖)
根據(jù)奇偶規(guī)則:交點(diǎn)數(shù)為2雄人,點(diǎn)P在圖形外部
根據(jù)非零環(huán)繞數(shù)規(guī)則:環(huán)繞數(shù)為-2,非零念赶,點(diǎn)P在圖形內(nèi)部
所以根據(jù)這兩組模式填充的結(jié)果就不一樣了
3础钠、測試
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
//同向的兩個(gè)圓
Path path = new Path();
path.addCircle(300, 300, 150, Path.Direction.CW);
path.addCircle(400, 300, 150, Path.Direction.CW);
path.setFillType(Path.FillType.WINDING);
// path.setFillType(Path.FillType.INVERSE_WINDING);
// path.setFillType(Path.FillType.EVEN_ODD);
// path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
canvas.drawPath(path, mPaint);
}
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
//反向的兩個(gè)圓
Path path = new Path();
path.addCircle(300, 300, 150, Path.Direction.CW);
path.addCircle(400, 300, 150, Path.Direction.CCW);
path.setFillType(Path.FillType.WINDING);
// path.setFillType(Path.FillType.INVERSE_WINDING);
// path.setFillType(Path.FillType.EVEN_ODD);
// path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
canvas.drawPath(path, mPaint);
}
4、分析
上面測試了同向圓叉谜、反向圓形成圖形的填充效果旗吁,可以看出:
(1)、Path的方向?qū)ζ媾家?guī)則沒啥影響停局,因?yàn)椴还苣阏蜻€是逆向阵漏,交點(diǎn)數(shù)不會(huì)改變,所以兩組測試中根據(jù)奇偶規(guī)則判斷的填充效果一致
(2)翻具、Path的方向直接影響非零環(huán)繞數(shù)規(guī)則履怯,同向時(shí),兩個(gè)圓相交區(qū)域內(nèi)的點(diǎn)環(huán)繞數(shù)為-2裆泳,非零叹洲,所以在圖形內(nèi)部,反向時(shí)工禾,兩個(gè)圓相交區(qū)域內(nèi)的點(diǎn)環(huán)繞數(shù)為0运提,在圖形外部.
5蝗柔、關(guān)于填充模式的其它幾個(gè)方法
public FillType getFillType()
獲取當(dāng)前的填充模式
public boolean isInverseFillType()
判斷當(dāng)前填充模式是否是反向規(guī)則 (也就是判斷是不是INVERSE_WINDING 、INVERSE_EVEN_ODD)
public void toggleInverseFillType()
切換填充規(guī)則 (即原有規(guī)則與反向規(guī)則之間相互切換)
十民泵、重置
public void reset()
public void rewind()
都是重置Path
reset會(huì)保留填充模式 (FillType)
rewind不保留填充模式癣丧,而是保留Path內(nèi)部內(nèi)部數(shù)據(jù)結(jié)構(gòu)