android之自定view之(八)----PathMeasure

PathMeasure是什么?

PathMeasure是用来对Path进行测量的,一般PathMeasure是和Path配合使用的,通过PathMeasure,我们可以知道Path路径上某个点的坐标、Path的长度等等.

构造方法:

方法名释义
PathMeasure()创建一个空的PathMeasure
PathMeasure(Path path, boolean forceClosed)创建 PathMeasure 并关联一个指定的Path(Path需要已经创建完成)。

公共方法:

返回值方法名释义
voidsetPath(Path path, boolean forceClosed)关联一个Path
booleanisClosed()是否闭合
floatgetLength()获取Path的长度
booleannextContour()跳转到下一个轮廓
booleangetSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)截取片段
booleangetPosTan(float distance, float[] pos, float[] tan)获取指定长度的位置坐标及该点切线值
booleangetMatrix(float distance, Matrix matrix, int flags)获取指定长度的位置坐标及该点Matrix

Android Demo

(1) 显示一个300*300的矩形

public class PathMeasureView extends View {

    private static final String TAG = "PathMeasureView";

    public PathMeasureView(Context context) {
        super(context);
        init(null, 0);
    }

    public PathMeasureView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0);
    }

    public PathMeasureView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle);
    }

    private void init(AttributeSet attrs, int defStyle) {
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(20f);
        Path sourcePath = new Path();
        sourcePath .addRect(300, 300, 600, 600, Path.Direction.CW);
        PathMeasure measure = new PathMeasure();
        measure.setPath(sourcePath , false);
        Log.e(TAG, "onDraw---measure.getLength() is " + measure.getLength());
        canvas.drawPath(sourcePath , paint);
    }

}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.readygo.pathmeasuredemo.PathMeasureView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

UI显示如图:
在这里插入图片描述
log显示:

 E/PathMeasureView: onDraw---measure.getLength() is 1200.0

可以看到长度为矩形的周长1200=300*4

(2)显示一个300*300的矩形和截取一个从0到450长度的部分矩形

我们要显示如下效果图:
在这里插入图片描述
关键代码:

        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(20f);

        Path sourcePath = new Path();
        sourcePath.addRect(300, 300, 600, 600, Path.Direction.CW);
        canvas.drawPath(sourcePath, paint);

        paint.setColor(Color.BLACK);
        PathMeasure measure = new PathMeasure();
        measure.setPath(sourcePath, false);
        Path dstPath = new Path();
        measure.getSegment(0, 450, dstPath, true);
        canvas.drawPath(dstPath, paint);

(3)我们添加一条直线和0到450的部分矩形图片
UI显示如图:
在这里插入图片描述
具体实现逻辑:

        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(20f);
        Path sourcePath = new Path();
        sourcePath.addRect(300, 300, 600, 600, Path.Direction.CW);
        PathMeasure measure = new PathMeasure();
        measure.setPath(sourcePath, false);
        Path dstPath = new Path();
        //给dstPath添加一条直线
        dstPath.lineTo(200, 800);
        measure.getSegment(0, 450, dstPath, true);
        canvas.drawPath(dstPath, paint);

如果我们将代码修改为:

measure.getSegment(0, 450, dstPath, false); //ture----false

则UI显示为:
在这里插入图片描述
(4) pathMeasure.getPosTan 实现动画
效果UI:
在这里插入图片描述
实现逻辑:

public class PathMeasureView extends View {

    private static final String TAG = "PathMeasureView";

    private Paint mPaint;
    private Path  mPath;
    private PathMeasure pathMeasure;
    private RectF mRectF;
    private float[] pos;
    private float distance;
    private int radius=20;

    public PathMeasureView(Context context) {
        super(context);
        init(null, 0);
    }

    public PathMeasureView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0);
    }

    public PathMeasureView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle);
    }

    private void init(AttributeSet attrs, int defStyle) {
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(20f);
        mPath = new Path();
        pathMeasure = new PathMeasure();
        mRectF = new RectF(300,300,600,600);
        pos = new float[2];
        startMove();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.i(TAG,"onDraw--pos[0]:"+pos[0]+"--pos[1]:"+pos[1]);
        mPath.reset();
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPath.addRect(mRectF, Path.Direction.CW);
        pathMeasure.setPath(mPath, false);
        canvas.drawPath(mPath, mPaint);

        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(pos[0], pos[1], radius, mPaint);
    }

    public void startMove() {
        ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
        animator.setInterpolator(new DecelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                distance = (float) animation.getAnimatedValue();
                Log.i(TAG,"onAnimationUpdate--distance:"+distance);
                pathMeasure.getPosTan(distance*pathMeasure.getLength(), pos, null);
                //postInvalidate();
                invalidate();
            }
        });
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setDuration(3000);
        animator.start();
    }

}

如果我们将矩形修改为一个圆形:

        //mPath.addRect(mRectF, Path.Direction.CW);
        mPath.addCircle(600,600,300, Path.Direction.CW);

效果如图:
在这里插入图片描述

(5) pathMeasure.getPosTan 实现动画显示一个图片
效果图:
在这里插入图片描述
实现逻辑为:

public class PathMeasureView extends View {

    private static final String TAG = "PathMeasureView";

    private Paint mPaint;
    private Path  mPath;
    private PathMeasure pathMeasure;
    private float[] pos;
    private float[] tan;
    private Bitmap mBitmap;
    private Matrix mMatrix;
    private float distance;

    public PathMeasureView(Context context) {
        super(context);
        init(null, 0,context);
    }

    public PathMeasureView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0,context);
    }

    public PathMeasureView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle,context);
    }

    private void init(AttributeSet attrs, int defStyle,Context context) {
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(20f);
        mPath = new Path();
        pathMeasure = new PathMeasure();
        pos = new float[2];
        tan = new float[2];
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 2;
        mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.arrow, options);
        mMatrix = new Matrix();
        startMove();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.i(TAG,"onDraw--pos[0]:"+pos[0]+"--pos[1]:"+pos[1]);
        mPath.reset();
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPath.addCircle(600,600,300, Path.Direction.CW);
        pathMeasure.setPath(mPath, false);
        canvas.drawPath(mPath, mPaint);

        mMatrix.reset();
        float degrees = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI);
        mMatrix.postRotate(degrees, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);
        mMatrix.postTranslate(pos[0]-mBitmap.getWidth()/2,pos[1]-mBitmap.getHeight()/2);
        canvas.drawBitmap(mBitmap, mMatrix, mPaint);
    }

    public void startMove() {
        ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
        animator.setInterpolator(new DecelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                distance = (float) animation.getAnimatedValue();
                Log.i(TAG,"onAnimationUpdate--distance:"+distance);
                pathMeasure.getPosTan(distance*pathMeasure.getLength(), pos, tan);
                //postInvalidate();
                invalidate();
            }
        });
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setDuration(3000);
        animator.start();
    }

}

参考资料

1.Android 自定义View学习(十六)——PathMeasure学习
https://www.jianshu.com/p/ac1250bccd3b/
2.安卓自定义View进阶-PathMeasure
https://www.gcssloop.com/customview/Path_PathMeasure
3.PathMeasure之迷径追踪
https://www.jianshu.com/p/3efa5341abcc
4.Android Path测量工具:PathMeasure
https://www.jianshu.com/p/82afb9c2e959?from=jiantop.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hfreeman2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值