自定义控件神器--PathMeasure

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mingyunxiaohai/article/details/89296295

我们平时自定义View的时候,经常会绘制path,想要求出path路径上的某个点的位置,很难通过一般的数学函数来计算,幸好系统给我们提供了一个PathMeasure可以用来测量一个path的路径,我们可以根据测量得到的值来绘制一些别的效果。

PathMeasure有两个构造方法

  public PathMeasure() {
        mPath = null;
        native_instance = native_create(0, false);
    }
  public PathMeasure(Path path, boolean forceClosed) {
        mPath = path;
        native_instance = native_create(path != null ? path.readOnlyNI() : 0,forceClosed);
    }

一个是有参数的,一个是没参数的

  • 有参数的构造方法中第一个很好理解就是需要测量的path,第二个参数的意思是是否计算path路径闭合的路径。如果是true,那么不管我们path是不是闭合了,它都会去计算闭合的路径。如果是false就不会计算。
  • 没有参数创建出来之后,可以通过 pathMeasure.setPath(mPath,false);方法把path和forceClosed这两个参数传进去

下面来看PathMeasure中的几个比较常用的方法

getSegment

给定一个起始点,一个结束点和一个空path对象,把给定的起点到终点的路径赋值给这个空的path。public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)。最后一个参数startWithMoveTo表示起点是否使用moveTo,用来保证截取的path第一个点的位置不变。从而保证截取的片段不会变形

它返回的是一个boolean值,如果截取到的路径长度是0就返回false,不是0就返回true。

下面来看一下使用getSegment的简单案例,在onDraw方法中

        mPath.reset();
        mFloat += 0.01;
        if (mFloat >= 1){
            mFloat = 0;
        }
        mPath.addCircle(getWidth()/2,getHeight()/2,200,Path.Direction.CW);
        mDst.reset();
        pathMeasure.setPath(mPath,false);
        float distance = pathMeasure.getLength() * mFloat;
        pathMeasure.getSegment(0, distance , mDst, true);
        canvas.drawPath(mDst, mPaint);
        invalidate();

使用一个0-1的成员变量mFloat来控制当前截取比例,每次调用invalidate的时候mFloat的值都会改变,这样就可以弄个简单的动画效果 效果如下
在这里插入图片描述

上面一直是从0来时截取如果我们改一下截取的位置

pathMeasure.getSegment(2*distance/3, distance, mDst, true);

第一个参数改成了2*distance/3,效果如下,类似一个加载动画的效果,这个参数可以随便改,更改的不同截取效果就不同

在这里插入图片描述

前面两个我们只绘制了我们截取的path,下面把原path也绘制上,截取的部分换一种颜色绘制,效果如下

在这里插入图片描述

getPosTan

getPosTan方法,可以获得path路径上某个点的位置和这个点的切线的值。public boolean getPosTan(float distance, float pos[], float tan[]) distance是当前需要截取的长度,pos是一个数组,如果不为空,可以给这个数组赋值,pos[0]是x坐标pos[1]是y坐标,tan跟也是个数组,tan[0],tan[1]代表切线的值,通过Math.atan2()方法传入tan[0],tan[1]可以获取到当前切线的角度。

下面看一个简单的例子

      mPath.reset();

        mFloat += 0.01;
        if (mFloat >= 1){
            mFloat = 0;
        }
       mPath.addCircle(getWidth()/2,getHeight()/2,200,Path.Direction.CW);
        pathMeasure.setPath(mPath,false);
       //用来记录位置
        float []pos = new float[2];
        //用来记录切点的位置
        float []tan = new float[2];
        float distance = pathMeasure.getLength() * mFloat;
        pathMeasure.getPosTan(distance,pos,tan);
        //计算出当前图片要旋转的角度
        float degree = (float) (Math.atan2(tan[1], tan[0]) * 180 / Math.PI);
        mMatrix.reset();
        //设置旋转角度和旋转中心
        mMatrix.postRotate(degree,mBitmap.getWidth() / 2,mBitmap.getHeight() / 2);
        //设置绘制的中心点与当前图片中心点重合
        mMatrix.postTranslate(pos[0]-mBitmap.getWidth() / 2,pos[1]-mBitmap.getHeight()/2);
        canvas.drawPath(mPath, mPaint);
        canvas.drawBitmap(mBitmap,mMatrix, mPaint);

效果如下:

在这里插入图片描述

通过getPosTan方法,获取到当前的角度,通过Matrix方法把一个图片旋转这个角度,然后绘制到圆圈上

除了使用getPosTan之外,还有一个稍微简单的方法可以获取到pos和tan的值,通过pathMeasure.getMatrix方法

public boolean getMatrix(float distance, Matrix matrix, int flags)

前两个值好理解,最后一个值flag,用来指定矩阵中需要返回那些参数,有两个值

public static final int POSITION_MATRIX_FLAG = 0x01;
public static final int TANGENT_MATRIX_FLAG = 0x02;

这两个值分别代表前面的pos和tan,例如下面的代码

       mPath.reset();
        mFloat += 0.01;
        if (mFloat >= 1){
            mFloat = 0;
        }
        //路径
        mPath.lineTo(0, 200);
        mPath.lineTo(300, 200);
        mPath.quadTo(450,100,600,200);
        mPath.lineTo(900, 200);
        pathMeasure.setPath(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);
        canvas.drawPath(mPath, mPaint);
        canvas.drawBitmap(mBitmap,mMatrix, mPaint);

效果:

在这里插入图片描述

源码地址

参考:https://www.jianshu.com/p/3efa5341abcc

猜你喜欢

转载自blog.csdn.net/mingyunxiaohai/article/details/89296295