Android PathMeasure詳細解讀

概念

路徑測量,一個用來測量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);

也可達到上圖效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章