Path 使用方法詳解
此篇是看了一名來自2.5次元的魔法師的文章後做的筆記,原文http://www.gcssloop.com/customview/Path_Bezier,大家可以看下,文很棒
1. 第一組:moveTo、setLastPoint 、lineTo 、close
方法:lineTo
public void lineTo (float x, float y)
例:畫兩條線
public PathView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化畫筆
mPaint = new Paint(); // 創建畫筆
mPaint.setColor(Color.BLACK); // 畫筆顏色 - 黑色
mPaint.setStyle(Paint.Style.STROKE); // 填充模式 - 描邊
mPaint.setStrokeWidth(10); // 邊框寬度 - 10
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//獲取寬高
width = h;
height = w;
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.translate(width / 2, height / 2); // 移動座標系到屏幕中心(寬高數據在onSizeChanged中獲取)
Path path = new Path(); // 創建Path
path.lineTo(200, 200); // lineTo 從默認點0,0到 200,200
path.lineTo(200, 0); //再從200,200 到點 200,0
canvas.drawPath(path, mPaint); // 繪製Path
}
結果如圖,黑色線圖像爲結果,圖中添加座標系,有利於理解
Path 默認點是座標原點0,0
事例代碼中調用了兩次lineTo,
第一次:path.lineTo(200, 200); //從0,0 到點A(200,200)的連線
第二次:path.lineTo(200, 0);//從A(200,200) 到點 B(200,0)的連線
方法 moveTo 和 setLstPoint
// moveTo
public void moveTo (float x, float y)
// setLastPoint
public void setLastPoint (float dx, float dy)
方法名 | 簡介 | 是否影響之前操作 | 是否影響之後操作 |
---|---|---|---|
moveTo | 移動下一次操作的起點位置 | 否 | 是 |
setLastPoint | 設置之前操作的最後一個點位置 | 是 | 是 |
方法 moveTo
例:
canvas.translate(width / 2, height / 2); // 移動座標系到屏幕中心(寬高數據在onSizeChanged中獲取)
Path path = new Path(); // 創建Path
path.lineTo(200, 200); // lineTo 從默認點0,0到 200,200
path.moveTo(200, 100); // moveTo 改變下一個點開始的位置
path.lineTo(200, 0); // 由於moveTo改變了開始位置,所以從200,100 到點 200,0
canvas.drawPath(path, mPaint); // 繪製Path
moveTo只改變下次操作的起點,在執行完第一次LineTo的時候,本來的默認點位置是A(200,200),但是moveTo將其改變成爲了C(200,100),所以在第二次調用lineTo的時候就是連接C(200,100) 到 B(200,0) 之間的直線
方法setLstPoint
例:
canvas.translate(width / 2, height / 2); // 移動座標系到屏幕中心(寬高數據在onSizeChanged中獲取)
Path path = new Path(); // 創建Path
path.lineTo(200, 200); // lineTo 從默認點0,0到 200,200
// path.moveTo(200, 100); // moveTo 改變下一個點開始的位置
path.setLastPoint(200,100); // setLastPoint 改變上一個點結束的位置
path.lineTo(200, 0); // 由於moveTo改變了開始位置,所以從200,100 到點 200,0
canvas.drawPath(path, mPaint); // 繪製Path
效果:
在執行完第一次的lineTo的時候,最後一個點是A(200,200),而setLastPoint更改最後一個點爲B(200,200)爲(200,100),所以在實際執行的時候,第一次的lineTo就不是從原點O到A(200,200)的連線了,而變成了從原點O到C(200,100)之間的連線了。
方法 close
public void close()
用於連接當前最後一個點和最初的點(如果兩個點不重合),形成一個閉合的圖形
結果:
2. 第二組:addXxx 與 arcTo
第一類(基本形狀)
// 圓形
public void addCircle (float x, float y, float radius, Path.Direction dir)
// 橢圓
public void addOval (RectF oval, Path.Direction dir)
// 矩形
public void addRect (float left, float top, float right, float bottom, Path.Direction dir)
public void addRect (RectF rect, Path.Direction dir)
// 圓角矩形
public void addRoundRect (RectF rect, float[] radii, Path.Direction dir)
public void addRoundRect (RectF rect, float rx, float ry, Path.Direction dir)
最後一個參數都是Path.Direction,意思是方向,繪製時點是你是逆時針還是順時針,在添加圖形時確定閉合順序(各個點的記錄順序)
類型 | 含義 |
---|---|
CW | 順時針 |
CCW | 逆時針 |
例子:畫一個矩形,順時針
canvas.translate(width / 2, height / 2); // 移動座標系到屏幕中心
Path path = new Path();
path.addRect(-200, -200, 200, 200, Path.Direction.CW);//順時針
canvas.drawPath(path, mPaint);
結果:
其實順時針和逆時針的表面結果是一樣的,只是過程不同,是怎麼畫成的
第二類方法(Path)
// path
public void addPath (Path src)
public void addPath (Path src, float dx, float dy)
public void addPath (Path src, Matrix matrix)
第一個方法:將兩個Path合併成爲一個
第二個方法比第一個方法多出來的兩個參數是將src進行了位移之後再添加進當前path中。
第三個方法是將src添加到當前path之前先使用Matrix進行變換。
例子:
canvas.translate(width / 2, height / 2); // 移動座標系到屏幕中心
canvas.scale(1,-1); // <-- 注意 翻轉y座標軸
Path path = new Path();
Path src = new Path();
path.addRect(-200,-200,200,200, Path.Direction.CW);//繪製一個矩形
src.addCircle(0,0,100, Path.Direction.CW);//座標原點繪製一個圓形
path.addPath(src,0,200);//將圓形添加到矩形的上 0,200的位置
canvas.drawPath(path,mPaint);
結果:
第三類方法(addArc與arcTo)
// addArc
public void addArc (RectF oval, float startAngle, float sweepAngle)
// arcTo
public void arcTo (RectF oval, float startAngle, float sweepAngle)
public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
方法區別
名稱 | 作用 | 區別 |
---|---|---|
addArc | 添加一個圓弧到path | 直接添加一個圓弧到path中 |
arcTo | 添加一個圓弧到path | 添加一個圓弧到path,如果圓弧的起點和上次最後一個座標點不相同,就連接兩個點 |
參數含義
參數 | 含義 |
---|---|
oval | 圓弧的外切矩形 |
startAngle | 開始角度 |
sweepAngle | 掃過角度(-360 <= sweepAngle < 360) |
forceMoveTo | 是否強制使用MoveTo |
sweepAngle取值範圍是 [-360, 360),不包括360,當 >= 360 或者 < -360 時將不會繪製任何內容, 對於360,你可以用一個接近的值替代,例如: 359.99
foreMoveTo | 含義 | 等價方法 |
---|---|---|
true | 將最後一個點移動到圓弧起點,即不連接最後一個點與圓弧起點 | public void addArc (RectF oval, float startAngle, float sweepAngle) |
false | 不移動,而是連接最後一個點與圓弧起點 | public void arcTo (RectF oval, float startAngle, float sweepAngle) |
例子(addArc):
canvas.translate(width / 2, height / 2); // 移動座標系到屏幕中心
canvas.scale(1,-1); // <-- 注意 翻轉y座標軸
Path path = new Path();
path.lineTo(100,100); //先畫個線
RectF oval = new RectF(0,0,300,300); //確定圓弧的外切矩形的位置
path.addArc(oval,0,270); //在已有的線的基礎上添加圓弧
// path.arcTo(oval,0,270,true); // <-- 和上面一句作用等價
canvas.drawPath(path,mPaint);
結果:
例子(arcTo):
canvas.translate(width / 2, height / 2); // 移動座標系到屏幕中心
canvas.scale(1,-1); // <-- 注意 翻轉y座標軸
Path path = new Path();
path.lineTo(100,100); //先畫個線
RectF oval = new RectF(0,0,300,300); //確定圓弧的外切矩形的位置
path.arcTo(oval,0,270); //在已有的線的基礎上添加圓弧,不移動,而是連接最後一個點與圓弧起點
// path.arcTo(oval,0,270,false); // <-- 和上面一句作用等價
canvas.drawPath(path,mPaint);
結果:
3. isEmpty 、isRect、 isConvex、 set 、offset
方法: isEmpty
判斷path中是否包含內容。
Path path = new Path();
Log.e("1",path.isEmpty()+"");
path.lineTo(100,100);
Log.e("2",path.isEmpty()+"");
結果:
com.sloop.canvas E/1: true
com.sloop.canvas E/2: false
方法:isRect
public boolean isRect (RectF rect)
判斷path是否是一個矩形,如果是一個矩形的話,會將矩形的信息存放進參數rect中
path.lineTo(0,400);
path.lineTo(400,400);
path.lineTo(400,0);
path.lineTo(0,0);
RectF rect = new RectF();
boolean b = path.isRect(rect);
Log.e("Rect","isRect:"+b+"| left:"+rect.left+"| top:"+rect.top+"| right:"+rect.right+"| bottom:"+rect.bottom);
結果:
com.sloop.canvas E/Rect: isRect:true| left:0.0| top:0.0| right:400.0| bottom:400.0
方法:set
public void set (Path src)
將新的path賦值到現有path。
canvas.translate(mWidth / 2, mHeight / 2); // 移動座標系到屏幕中心
canvas.scale(1,-1); // <-- 注意 翻轉y座標軸
Path path = new Path(); // path添加一個矩形
path.addRect(-200,-200,200,200, Path.Direction.CW);
Path src = new Path(); // src添加一個圓
src.addCircle(0,0,100, Path.Direction.CW);
path.set(src); // 大致相當於 path = src;
canvas.drawPath(path,mPaint);
結果:
方法 offset
public void offset (float dx, float dy)
public void offset (float dx, float dy, Path dst)
對path進行一段平移,它和Canvas中的translate作用很像,但Canvas作用於整個畫布,而path的offset只作用於當前path。
方法第最後的參數 Path dst 是存儲平移後的path的
dst狀態 | 效果 |
---|---|
dst不爲null | 將當前path平移後的狀態存入dst中,不會影響當前path |
dat爲空 | 平移將作用於當前path,相當於第一種方法 |
// ====== 方法 offset ========
canvas.translate(width/2 , height / 2); // 移動座標系到屏幕中心
canvas.scale(1,-1); // <-- 注意 翻轉y座標軸
Path path = new Path(); // path中添加一個圓形(圓心在座標原點)
path.addCircle(0,0,100, Path.Direction.CW);
Path dst = new Path(); // dst中添加一個矩形
dst.addRect(-200,-200,200,200, Path.Direction.CW);
path.offset(250,0,dst); // 平移
canvas.drawPath(path,mPaint); // 繪製path
mPaint.setColor(Color.BLUE); // 更改畫筆顏色
canvas.drawPath(dst,mPaint); // 繪製dst
結果:
平移之前:
平移後:
從運行效果圖可以看出,雖然我們在dst中添加了一個矩形,但是並沒有表現出來,所以,當dst中存在內容時,dst中原有的內容會被清空,而存放平移後的path。