Android Canvas之Path操作


接上篇,Android自己定義View工具:Paint&Canvas(二)

上一篇中介紹的Canvas繪制圖形僅僅能畫一些常規圖形(圓,橢圓,矩形等)。假設想繪制更復雜的圖形,Path神器來了。

Path是什么?
Path類將多種復合路徑(多個輪廓。如直線段、二次曲線、立方曲線)封裝在其內部的幾何路徑。

怎樣繪制Path:
通過設置Paint的Style(FILL、STROKE、FILL_AND_STROKE),然后調用canvas.drawPath(path, paint);Path還能夠用於剪切或者在路徑上繪制文本(canvas.drawTextOnPath())。

Path有兩個構造函數:

Path() // 空的構造函數
Path(Path src) //創建一個新的路徑,而且從src路徑里賦值內容

Path經常用法一覽表:

Path經常用法 備注
線操作  
lineTo、rLineTo 繪制線
點操作  
moveTo、rMoveTo 改變后面操作的起始點位置
setLastPoint 改變前面操作中最后點的位置
加入常規圖形  
addRect 繪制矩形
addRoundRect 繪制圓角矩形
addCircle 繪制圓
addOval 繪制橢圓
addArc、arcTo 繪制圓弧
閉合path  
close 假設連接Path起點和終點能形成一個閉合圖形,則會將起點和終點連接起來形成一個閉合圖形
貝塞爾曲線  
quadTo、rQuadTo、cubicTo、rCubicTo 貝塞爾曲線
  • 線操作
lineTo(float x, float y) //加入當前點到目標點(x,y)構成的直線到path
rLineTo(float dx, float dy) //基於當前坐標系,即以path最后的那個點
//為坐標系原點(0,0),假設前面沒有path的點。默認是屏幕左上角(0,0).

注:lineTo、rLineTo起始點默認是屏幕左上角的坐標系原點(0,0)。
演示樣例:

//設置Paint
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
//設置Path
Path path = new Path();
//屏幕左上角(0,0)到(200,400)畫一條直線
path.lineTo(200, 400);
//(200, 400)到(400,600)畫一條直線
path.lineTo(400, 600);
//以(400,600)為起始點(0,0)偏移量為(400,600)畫一條直線。
//其終點坐標實際在屏幕的位置為(800,1200)
path.rLineTo(400, 600);
canvas.drawPath(path, mPaint);

效果圖:

                                                  


  • 點操作
moveTo(float x, float y) //改變接下來操作的起點位置為(x,y)
rMoveTo(float dx, float dy) //接下來要操作的起點位置為(x+dx,y+dy)
setLastPoint(float dx, float dy) //改變前一步操作點的位置。會改變前一步的操作

先來看 moveTo和rMoveTo的差別 ,演示樣例:

//初始化Paint
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
//初始化Path
Path path = new Path();
//將坐標系原點從(0,0)移動到(100,100)
path.moveTo(100, 100);
//畫從(100,100)到(400,400)之間的直線
path.lineTo(400, 400);
//path.rMoveTo(0, 100); //臨時凝視
path.lineTo(400, 800);
canvas.drawPath(path, mPaint);

效果圖:

                                                                       

上面代碼中,打開凝視的path.rMoveTo(0, 100),意為下一步操作起點位置由(400,400)變為(400+0,400+100)即為(400,500),效果圖:

                                               


接下來看下,moveTo和setLastPoint的差別,相同用上面的代碼,加上path.setLastPoint(100, 800),例如以下:

//初始化Paint
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
//初始化Path
Path path = new Path();
//將坐標系原點從(0,0)移動到(100,100)
path.moveTo(100, 100);
//畫從(100,100)到(400,400)之間的直線
path.lineTo(400, 400);
//新加的setLastPoint
path.setLastPoint(100, 800);
path.lineTo(400, 800);
canvas.drawPath(path, mPaint);

效果圖:

                                              


虛線本來是沒設置setLastPoint之前的路徑,設置setLastPoint(100,800)后。影響到了前一步lineTo(400,400)操作,變成了lineTo(100,800),最后結果就變成了紅顏色的path路徑,能夠得出結論:moveTo影響的是后面操作的起點位置。不會影響之前的操作;而 setLastPoint改變前一步操作最后一個點的位置,不僅影響前一步操作,同一時候也會影響后一步操作!

  • 繪制常規圖形
//繪制圓
addCircle(float x, float y, float radius, Direction dir) 
 //繪制橢圓
addOval(RectF oval, Direction dir)
addOval(float left, float top, float right, float bottom, Direction dir) 
//繪制矩形
addRect(RectF rect, Direction dir) 
addRect(float left, float top, float right, float bottom, Direction dir) 
//繪制圓角矩形
addRoundRect(RectF rect, float rx, float ry, Direction dir) 
addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir)
addRoundRect(RectF rect, float[] radii, Direction dir)
addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)

全部方法里面都有一個共同的參數Direction :

Direction 備注
Path.Direction.CCW counter-clockwise ,沿逆時針方向繪制
Path.Direction.CW clockwise ,沿順時針方向繪制

Direction 用法演示樣例:

//初始化Paint
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2f);
paint.setTextSize(40f);
//初始化Path
Path path = new Path();
//以(600,600)為圓心。300為半徑繪制圓 
//Path.Direction.CW順時針繪制圓 Path.Direction.CCW逆時針繪制圓
path.addCircle(600, 600, 300, Path.Direction.CW);
//沿path繪制文字
canvas.drawTextOnPath("痛苦最好是別人的,快樂才是自己的;麻煩將是臨時的,朋友總是永恆的。

", path, 0, 0, paint); canvas.drawPath(path, paint);


效果圖:

                                              


效果非常明顯。設置為Path.Direction.CW時,文字沿順時針繪制;設置為Path.Direction.CCW時,文字沿逆時針繪制。

繪制常規圖形演示樣例:

//初始化Paint
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
Path path = new Path();
//以(400,200)為圓心,半徑為100繪制圓
path.addCircle(400, 200, 100, Path.Direction.CW);

//繪制橢圓
RectF rectF = new RectF(100, 350, 500, 600);
//第一種方法繪制橢圓
path.addOval(rectF, Path.Direction.CW);
//另外一種方法繪制橢圓
path.addOval(600, 350, 1000, 600, Path.Direction.CW);

//繪制矩形
RectF rect = new RectF(100, 650, 500, 900);
//第一種方法繪制矩形
path.addRect(rect, Path.Direction.CW);
//第一種方法繪制矩形
path.addRect(600, 650, 1000, 900, Path.Direction.CCW);

//繪制圓角矩形
RectF roundRect = new RectF(100, 950, 300, 1100);
//第一種方法繪制圓角矩形
path.addRoundRect(roundRect, 20, 20, Path.Direction.CW);
//另外一種方法繪制圓角矩形
path.addRoundRect(350, 950, 550, 1100, 10, 50, Path.Direction.CCW);
//第三種方法繪制圓角矩形 
//float[] radii中有8個值,依次為左上角,右上角,右下角,左下角的rx,ry
RectF roundRectT = new RectF(600, 950, 800, 1100);
path.addRoundRect(roundRectT, new float[]{50, 50, 50, 50, 50, 50, 0, 0}, Path.Direction.CCW);
//第四種方法繪制圓角矩形
path.addRoundRect(850, 950, 1050, 1100,new float[]{0, 0, 0, 0,50, 50, 50, 50}, Path.Direction.CCW);
canvas.drawPath(path, paint);

效果圖:

                                                         


繪制圓弧:

 

//繪制圓弧
addArc(RectF oval, float startAngle, float sweepAngle)
addArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle)

//forceMoveTo:是否強制將path最后一個點移動到圓弧起點。
//true是強制移動,即為不連接兩個點。false則連接兩個點
arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)
arcTo(RectF oval, float startAngle, float sweepAngle)
arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)

addArc和arcTo都是加入圓弧到path中。只是他們之間還是有差別的: addArc是直接加入圓弧到path中,而arcTo會推斷要繪制圓弧的起點與繪制圓弧之前path中最后的點是否是同一個點,假設不是同一個點的話,就會連接兩個點。
演示樣例:

//在(400, 200, 600, 400)區域內繪制一個300度的圓弧
RectF rectF = new RectF(400, 200, 600, 400);
path.addArc(rectF, 0, 300);
//在(400, 600, 600, 800)區域內繪制一個90度的圓弧。而且不連接兩個點
RectF rectFTo = new RectF(400, 600, 600, 800);
path.arcTo(rectFTo, 0, 90, true);
//等價於path.addArc(rectFTo, 0, 90);
canvas.drawPath(path, paint);

效果圖:

                                                 


改動一下代碼:

 

//在(400, 200, 600, 400)區域內繪制一個300度的圓弧
RectF rectF = new RectF(400, 200, 600, 400);
path.addArc(rectF, 0, 300);
//在(400, 600, 600, 800)區域內繪制一個90度的圓弧,而且連接兩個點
RectF rectFTo = new RectF(400, 600, 600, 800);
path.arcTo(rectFTo, 0, 90,false);
//等價於path.arcTo(rectFTo, 0, 90);
canvas.drawPath(path, paint);

對照發現我們僅僅是將arcTo最后一個參數變成了false,即連接繪制圓弧之前path的最后一個點和繪制圓弧的起點。效果圖:



  • 閉合path
path.close();

假設path的終點和起始點不是同一個點的話,close()連接這兩個點,形成一個封閉的圖形,演示樣例:

//初始化Paint
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
//初始化Path
Path path = new Path();
//將坐標原點移動到(300,300,)
path.moveTo(300, 300);
//連接(300, 300)和(300, 600)成一條線
path.lineTo(300, 600);
//連接(300, 600)和(600, 600)成一條線
path.lineTo(600, 600);
//path.close();臨時凝視
canvas.drawPath(path, paint);

效果圖:

                                                     


改動一下代碼。將上面的path.close()打開。效果圖:

                                                     


能夠調用close()后,連接了path的起始點和終點形成了一個封閉圖形!

貝塞爾曲線內容較多。放在下一篇了!



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM