概念
路徑測量,一個用來測量Path的工具類
常用API
常用API如Path長度測量,Path跳轉,Path片段獲取、
構造方法 | |
---|---|
PathMeasure() | |
PathMeasure(Path path, boolean forceClosed) | forceClosedPath決定是否需要閉合 |
基本代碼
public class PathMeasureView extends View {
private Paint mPaint = new Paint();
private Paint mLinePaint = new Paint(); //座標系
private Bitmap mBitmap;
public PathMeasureView(Context context) {
super(context);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(4);
mLinePaint.setStyle(Paint.Style.STROKE);
mLinePaint.setColor(Color.RED);
mLinePaint.setStrokeWidth(6);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, mLinePaint);
canvas.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight(), mLinePaint);
//將canvas中心移動到屏幕的中心,兩條線相交的位置
canvas.translate(getWidth() / 2, getHeight() / 2);
....
}
}
PathMeasure無參構造
pathMeasure需要通過setPath方法關聯一個創建好的path,要不無法使用。
PathMeasure.setPath()
public void setPath (Path path, boolean forceClosed)
通過PathMeasure.setPath的方式來將Path和PathMeasure進行綁定。
如果Path進行了調整,需要重新調用setPath方法進行關聯,也就是說 pathMeasure.getLength()方法得到的值的之前的。
需要重新調用setPath方法來更新值。
PathMeasure有參構造
public PathMeasure (Path path, boolean forceClosed)
PathMeasure | |
---|---|
forceClosed | forceClosedPath決定是否需要閉合 |
forceClosed
forceClosed,就是Path最終是否需要閉合,如果爲True的話,則不管關聯的Path是否是閉合的,都會被閉合, pathMeasure.getLength()長度就爲閉合後的長度。
示例:
Path path = new Path();
path.lineTo(0,200);
path.lineTo(200,200);
path.lineTo(200,0);
/**
* pathMeasure需要關聯一個創建好的path, forceClosed會影響Path的測量結果
*/
PathMeasure pathMeasure = new PathMeasure();
pathMeasure.setPath(path, true);
Log.e("TAG", "onDraw:forceClosed=true "+ pathMeasure.getLength());
PathMeasure pathMeasure2 = new PathMeasure();
pathMeasure2.setPath(path, false);
Log.e("TAG", "onDraw:forceClosed=false "+ pathMeasure2.getLength());
canvas.drawPath(path, mPaint);
log日誌
E/TAG: onDraw:forceClosed=true 800.0
E/TAG: onDraw:forceClosed=false 600.0
getSegment
public boolean getSegment (float startD, float stopD, Path dst, boolean startWithMoveTo)
給定起始和停止距離,在dst中返回中間的段。
如果段的長度爲零,返回false,否則返回true。
如果startD >= stopD,則返回false(並保持dst不變)。
getSegment | |
---|---|
startD | 開始截取位置距離path的長度(0…getLength()) |
stopD | 結束截取的位置距離path的長度(0…getLength()) |
startWithMoveTo | 起始點是否使用moveTo 進行移動,用於保證截取的第一個位置的點path不變。 |
dst | 截取的 Path 將會添加到 dst 中 |
首先在屏幕中間構造一個正方形
canvas.translate(getWidth() / 2, getHeight() / 2);
Path path = new Path();
path.addRect(-200,-200, 200,200, Path.Direction.CW);
canvas.drawPath(path, mPaint);
我們再用一個直線來存儲getSegment所獲取到的段。
canvas.translate(getWidth() / 2, getHeight() / 2);
Path path = new Path();
path.addRect(-200,-200, 200,200, Path.Direction.CW);
//dst 設置了畫筆顏色紅色
Path dst = new Path();
PathMeasure pathMeasure = new PathMeasure(path, false);
//截取一部分存入dst中,並且使用moveTo保持截取得到的Path第一個點位置不變。
pathMeasure.getSegment(300, 1000, dst, true);
canvas.drawPath(path, mPaint);
canvas.drawPath(dst, mLinePaint);
pathMeasure.getSegment(300, 1000, dst, true);中
dst 爲紅色線的部分
300爲距離 path.addRect(-200,-200, 200,200, Path.Direction.CW);中left(-200)的距離300
1000位距離 path.addRect(-200,-200, 200,200, Path.Direction.CW);中left(-200)的距離1000
true 使用moveTo 進行移動
目前我們設置爲true,如果設置爲false。
起始點並沒有移動,而是從之前的canvas.translate(getWidth() / 2, getHeight() / 2);
移動的點開始繪製。
nextContour | 跳轉到下一個輪廓是否成功,失敗返回false,成功返回true |
---|
–
getPosTan(float distance, float[] pos, float[] tan) | 獲取指定長度的位置座標及該點切線值tangle |
---|---|
distance | 距離path起點的長度 |
pos | 長度爲2的浮點型數組,分別表示x,y座標 |
tan | 長度爲2的浮點型數組,分別表示當前點在曲線上的方向,可以獲取到切線方向與x軸的夾角x,y |
定義pos和tan
private float[] pos = new float[2];
private float[] tan = new float[2];
畫一個圓
mPath.addCircle(0,0,200, Path.Direction.CW);
canvas.drawPath(mPath, mPaint);
PathMeasure pathMeasure = new PathMeasure(mPath, false);
pathMeasure.getPosTan(0,pos,tan);
Log.e("TAG", "onDraw: pos[0]="+pos[0]+";pos[1]="+pos[1]);
Log.e("TAG", "onDraw: tan[0]="+tan[0]+";tan[1]="+tan[1]);
log結果:
E/TAG: onDraw: pos[0]=200.0;pos[1]=0.0
E/TAG: onDraw: tan[0]=0.0;tan[1]=1.0
public class PathMeasureView extends View {
private Paint mPaint = new Paint();
private Bitmap mBitmap;
public PathMeasureView(Context context) {
super(context);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(4);
//縮小圖片
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.arrow,options);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(getWidth() / 2, getHeight() / 2);
mPath.reset();
mPath.addCircle(0,0,200, Path.Direction.CW);
canvas.drawPath(mPath, mPaint);
mFloat += 0.01;
if (mFloat >= 1){
mFloat = 0;
}
PathMeasure pathMeasure = new PathMeasure(mPath, false);
pathMeasure.getPosTan(mFloat*pathMeasure.getLength(),pos,tan);
//計算出當前的切線與x軸夾角的度數
double degrees = Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI;
mMatrix.reset();
//進行角度旋轉
mMatrix.postRotate((float) degrees, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);
//將圖片的繪製點中心與當前點重合
mMatrix.postTranslate(pos[0] - mBitmap.getWidth() / 2, pos[1]-mBitmap.getHeight() / 2);
canvas.drawBitmap(mBitmap,mMatrix, mPaint);
canvas.drawBitmap(mBitmap,mMatrix, mPaint);
invalidate();
}
private Matrix mMatrix = new Matrix();
private float[] pos = new float[2];
private float[] tan = new float[2];
private Path mPath = new Path();
private float mFloat;
}
getMatrix(float distance, Matrix matrix, int flags) | 獲取指定長度的位置座標及該點Matrix(矩陣) |
---|---|
distance | 距離path起點的長度 |
matrix | 將信息存放在matrix中 |
flags | 指定存放信息的類型,有兩個POSITION_MATRIX_FLAG表示位置信息,TANGENT_MATRIX_FLAG表示當前點在曲線上的方向,對應getPosTan中的tan |
如下代碼
PathMeasure pathMeasure = new PathMeasure(mPath, false);
// 將pos信息和tan信息保存在mMatrix中
pathMeasure.getMatrix(pathMeasure.getLength() * mFloat, mMatrix, PathMeasure.POSITION_MATRIX_FLAG | PathMeasure.TANGENT_MATRIX_FLAG);
// 將圖片的旋轉座標調整到圖片中心位置
mMatrix.preTranslate(-mBitmap.getWidth() / 2, -mBitmap.getHeight() / 2);
也可達到上圖效果