接上篇,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的起始點和終點形成了一個封閉圖形!
貝塞爾曲線內容較多,放在下一篇了!
Tags: Android 一覽表 坐標系 close Style
文章來源: