android之自定view之(八)----PathMeasure
PathMeasure是什么?
PathMeasure是用来对Path进行测量的,一般PathMeasure是和Path配合使用的,通过PathMeasure,我们可以知道Path路径上某个点的坐标、Path的长度等等.
构造方法:
方法名 | 释义 |
---|---|
PathMeasure() | 创建一个空的PathMeasure |
athMeasure(Path path, boolean forceClosed) | 创建 PathMeasure 并关联一个指定的Path(Path需要已经创建完成)。 |
公共方法:
返回值 | 方法名 | 释义 |
---|---|---|
void | setPath(Path path, boolean forceClosed) | 关联一个Path |
boolean | isClosed() | 是否闭合 |
float | getLength() | 获取Path的长度 |
boolean | nextContour() | 跳转到下一个轮廓 |
boolean | getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) | 截取片段 |
boolean | getPosTan(float distance, float[] pos, float[] tan) | 获取指定长度的位置坐标及该点切线值 |
boolean | getMatrix(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