Android中PathMeasure的使用

PathMeasure使用介绍

  • 介绍

    AndroidSDK提供的一个非常有用的API来对一个Path路径点的坐标追踪,它可以认为是一个Path的坐标计算器。

  • 使用
    • 初始化
      构造方法共有两个:PathMeasure(),PathMeasure(Path path, boolean forceClosed)
      1、默认无参构造方法

      PathMeasure pathMeasure = new PathMeasure();
      

      初始化PathMeasure后,可以通过PathMeasure.setPath(Path path, boolean forceClosed)的方式来将Path和PathMeasure进行绑定。被关联的Path必须是已经创建好的,如果关联之后Path内容进行了更改,则需要使用setPath方法重新关联。
      2、有参构造方法

      PathMeasure pathMeasure = new PathMeasure(path, false);
      

      同样,被关联的Path也必须是已经创建好的,如果关联之后Path内容进行了更改,则需要使用setPath方法重新关联。关于第二个参数forceClosed,不论forceClosed设置为何种状态(true或者false), 都不会影响原有Path的状态,即Path与PathMeasure关联之后,之前的的Path不会有任何改变。forceClosed的设置状态会影响测量结果,如果Path未闭合但在与PathMeasure关联的时候设置forceClosed为true时,测量结果可能会比Path实际长度稍长一点,获取到的是该Path闭合时状态的长度。同样如果Path闭合但在与PathMeasure关联的时候设置forceClosed为false时,测量结果可能会比Path实际长度稍短一点,就是说forceClosed的设置只会影响测量的结果。

    • 方法
      1、float getLength():
      这个方法的使用比较广泛,其作用就是获取计算的路径长度。
      2、boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo):
      用于获取Path的一个片段。参数解释如下:
      startD:开始截取位置距离Path起点的长度
      stopD:结束截取位置距离Path起点的长度
      dst:截取的Path将会添加到dst中
      startWithMoveTo:起始点是否使用moveTo
      3、boolean getPosTan(float distance, float pos[], float tan[]):
      用于得到路径上某一长度的位置以及该位置的正切值
      distance:获取点距离起点的长度
      pos:获取点的坐标
      tan:获取点的正切值,tan是tangent的缩写,即中学中常见的正切,其中tan[0]是邻边边长,tan[1]是对边边长,而Math中atan2方法是根据正切是数值计算出该角度的大小,得到的单位是弧度,所以上面又将弧度转为了角度。
      4、boolean nextContour():
      Path可以由多条曲线构成,但不论是getLength,getgetSegment或者是其它方法,都只会在其中第一条线段上运行,而这个nextContour就是用于跳转到下一条曲线到方法,如果跳转成功,则返回true, 如果跳转失败,则返回false。
      5、boolean getMatrix(float distance, Matrix matrix, int flags):
      用于得到路径上某一长度的位置以及该位置的正切值的矩阵
      distance:距离Path起点的长度
      matrix:根据falgs封装好的matrix
      flags:规定哪些内容会存入到matrix中,POSITION_MATRIX_FLAG(位置)、ANGENT_MATRIX_FLAG(正切值)

    • 应用

      示例1效果图(getPosTan方法应用):
      Android中PathMeasure的使用_第1张图片

      实现代码:

      public class PathMeasureView extends View {
      
          private Paint mPaint;
          private Path path;
          private PathMeasure mPathMeasure;
          private float mAnimatorValue;
          private float mLength;
          private float[] pos;
          private float[] tan;
          private Bitmap bitmap;
      
          public PathMeasureView(Context context, AttributeSet attrs) {
              super(context, attrs);
              mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
              mPaint.setStyle(Paint.Style.STROKE);
              mPaint.setColor(Color.RED);
              mPaint.setStrokeWidth(5);
              mPaint.setStrokeCap(Paint.Cap.ROUND);
              mPaint.setAntiAlias(true);
              path = new Path();
              path.moveTo(0, 0);
              path.quadTo(100, 200, 200, 0);
              path.quadTo(300, -200, 400, 0);
              mPathMeasure = new PathMeasure(path, false);
              mLength = mPathMeasure.getLength();
              pos = new float[2];
              tan = new float[2];
              bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.timg);
      
              ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
              valueAnimator.setDuration(5000);
              valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                  @Override
                  public void onAnimationUpdate(ValueAnimator animation) {
                      mAnimatorValue = (float) animation.getAnimatedValue();
                      postInvalidate();
                  }
              });
              valueAnimator.setInterpolator(new LinearInterpolator());
              valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
              valueAnimator.start();
          }
      
          @Override
          protected void onDraw(Canvas canvas) {
              super.onDraw(canvas);
              canvas.save();
              canvas.translate(200, 400);
              canvas.drawPath(path, mPaint);
              mPathMeasure.getPosTan(mLength * mAnimatorValue, pos, tan);
              float degrees = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI);
              canvas.rotate(degrees, pos[0], pos[1]);
              canvas.drawBitmap(bitmap, pos[0] - bitmap.getWidth()/2, pos[1] - bitmap.getHeight(), mPaint);
              canvas.restore();
          }
      }
      

      示例2效果(getSegment应用):


      Android中PathMeasure的使用_第2张图片
      gaollg2.GIF

      实现代码:

      public class PathMeasureView extends View {
      
          private Paint mPaint;
          private Path path;
          private PathMeasure mPathMeasure;
          private float mAnimatorValue;
          private Path mDst;
          private float mLength;
      
          public PathMeasureView(Context context, AttributeSet attrs) {
              super(context, attrs);
              mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
              mPaint.setStyle(Paint.Style.STROKE);
              mPaint.setColor(Color.RED);
              mPaint.setStrokeWidth(5);
              mPaint.setStrokeCap(Paint.Cap.ROUND);
              mPaint.setAntiAlias(true);
              path = new Path();
              path.addCircle(0, 0, 100, Path.Direction.CW);
              mPathMeasure = new PathMeasure(path, false);
              mDst = new Path();
              mLength = mPathMeasure.getLength();
      
              ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 2);
              valueAnimator.setDuration(5000);
              valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                  @Override
                  public void onAnimationUpdate(ValueAnimator animation) {
                      mAnimatorValue = (float) animation.getAnimatedValue();
                      postInvalidate();
                  }
              });
              valueAnimator.setInterpolator(new LinearInterpolator());
              valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
              valueAnimator.start();
          }
      
          @Override
          protected void onDraw(Canvas canvas) {
              super.onDraw(canvas);
      
              mDst.reset();
              float start, stop;
              if (mAnimatorValue <= 1) {
                  start = 0;
                  stop = mLength * mAnimatorValue;
              } else {
                  start = (mAnimatorValue - 1) * mLength;
                  stop = mLength;
              }
              mPathMeasure.getSegment(start, stop, mDst, true);
              canvas.translate(200, 400);
              canvas.drawPath(mDst, mPaint);
          }
      }
      

你可能感兴趣的:(Android中PathMeasure的使用)