您当前的位置: 首页 >  ui

【高级UI】【020】通过PathMeasure测量Path

发布时间:2021-11-14 17:54:58 ,浏览量:5

什么是PathMeasure

PathMeasure是用来对Path相关数据进行测量的工具类

它可以测出Path的长度,点位置,切线斜率,判断路径是否闭合,截取子路径等功能

PathMeasure函数接口

//绑定Path,如果曲线没有闭合,可以通过forceClosed强制闭合 public void setPath(Path path, boolean forceClosed); //计算路径总长度 public float getLength(); //获取路径指定位置的坐标和切线方向 //这个位置,是通过指定点到起点的路径长度来表示的 //pos中的值为[x,y],tan中的值为[Δx,Δy] boolean getPosTan(float distance, float pos[], float tan[]); //获取指定位置的坐标和正切 //可以通过flag指定全部获取,还是只获取其中一个 //flags = PathMeasure.POSITION_MATRIX_FLAG | PathMeasure.TANGENT_MATRIX_FLAG //位置信息存到矩阵中,可用来进行平移变换,正切信息存到矩阵中,可用来进行旋转变换 boolean getMatrix(float distance, Matrix matrix, int flags); //截取start-end位置的子路径,存入dst变量 //start和end是点到路径起点的总距离 //注意,这个函数是将新的子路径,直接拼接到dst路径上面,它并不会清除dst路径中已有的数据 //如果需要清除dst路径中的已有数据,需要自己调用reset方法 //startWithMoveTo=true,表示通过moveTo的方式连接新路径 //startWithMoveTo=false,表示通过lineTo的方式连接新路径 public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) //如果一个路径是不连续的,则它会包含多个子路径 //getSegment和getLength等,默认是在首个子路径上计算长度和截取部分 //如果想在其它子路径上操作,则需要调用nextContour,调至下个子路径 public boolean nextContour() //判断当前子路径是否闭合 boolean isClosed(); 

PathMeasure应用案例

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 核心代码

package com.android.architecture; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; import android.util.AttributeSet; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; //进度加载动画 @SuppressWarnings("all") public class B extends View { Paint paint = new Paint(); Path srcPath = new Path(); Path dstPath = new Path(); PathMeasure pathMeasure = new PathMeasure(); float progress; float length; public B(Context context) { this(context, null); } public B(Context context, AttributeSet attributeSet) { super(context, attributeSet); init(context, attributeSet); //开始进度动画 //进度动画有加速减速过程,比我们自己去匀速控制进度更自然 ValueAnimator anim = ValueAnimator.ofFloat(0, 1); anim.addUpdateListener(animation -> { progress = (float) animation.getAnimatedValue(); invalidate(); }); anim.setDuration(2000); anim.setRepeatCount(ValueAnimator.INFINITE); anim.setInterpolator(new AccelerateDecelerateInterpolator()); anim.start(); } protected void init(Context context, AttributeSet attributeSet) { //关闭硬件加速 setLayerType(LAYER_TYPE_SOFTWARE, null); //创建画笔 paint.setAntiAlias(true); paint.setColor(Color.RED); paint.setStrokeWidth(10); paint.setStyle(Paint.Style.STROKE); //完整路径 srcPath.addCircle(400, 400, 200, Path.Direction.CCW); //计算路径总长度 pathMeasure.setPath(srcPath, true); length = pathMeasure.getLength(); } @Override protected void onDraw(Canvas canvas) { //画局部弧 double arcRatio = 0.5 - Math.abs(0.5 - progress); double stop = length * progress; double start = stop - length * arcRatio; dstPath.reset(); pathMeasure.getSegment((float) start, (float) stop, dstPath, true); canvas.drawPath(dstPath, paint); } } 
package com.android.architecture; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; import android.util.AttributeSet; import android.view.View; //阿童木沿圆形太阳漫游动画 @SuppressWarnings("all") public class A extends View { Bitmap bitmap; Paint paint; Matrix matrix = new Matrix(); float progress = 0; public A(Context context) { this(context, null); } public A(Context context, AttributeSet attributeSet) { super(context, attributeSet); init(context, attributeSet); } private void init(Context context, AttributeSet attributeSet) { //图片缩小 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(context.getResources(), R.drawable.atm, options); options.inSampleSize = options.outWidth / 50; options.inJustDecodeBounds = false; bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.atm, options); //创建画笔 paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.RED); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); } @Override protected void onDraw(Canvas canvas) { //计算动画进度 progress += 0.005; if (progress >= 1) progress = 0; //画底色 canvas.drawColor(Color.WHITE); //从中间开始画 canvas.translate(getMeasuredWidth() / 2, getMeasuredHeight() / 2); //顺时针画圆 Path path = new Path(); path.addCircle(0, 0, 200, Path.Direction.CW); //获得圆上指定点的位置和正切 //这两个属性,可以作为图片的平移距离和旋转角度来使用 //Path上点的位置,就是绘图时,图片左上角的位置,点切线的方向,就是图片旋转的方向 PathMeasure pathMeasure = new PathMeasure(path, false); float distance = pathMeasure.getLength() * progress; pathMeasure.getMatrix(distance, matrix, PathMeasure.POSITION_MATRIX_FLAG | PathMeasure.TANGENT_MATRIX_FLAG); //动画左下角与圆吻合,因此要先平移一下,调整绘图的起点位置 matrix.preTranslate(0, -bitmap.getHeight()); //画平移旋转后的图像 canvas.drawPath(path, paint); canvas.drawBitmap(bitmap, matrix, paint); //刷新下一帧 postInvalidateDelayed(30); } } 
package com.android.architecture; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.animation.LinearInterpolator; //阿童木沿波浪冲锋 @SuppressWarnings("all") public class C extends View { public static final int WAVE_LENGTH = 600; Bitmap bitmap; Paint paint = new Paint(); Path path = new Path(); PathMeasure pathMeasure; Matrix matrix = new Matrix(); ValueAnimator anim; float progress; int positive = 1; public C(Context context) { this(context, null); } public C(Context context, AttributeSet attributeSet) { super(context, attributeSet); init(context, attributeSet); } protected void init(Context context, AttributeSet attributeSet) { //图片缩小 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(context.getResources(), R.drawable.atm, options); options.inSampleSize = options.outWidth / 50; options.inJustDecodeBounds = false; bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.atm, options); //创建画笔 paint.setAntiAlias(true); paint.setColor(Color.RED); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); //开始进度动画 anim = ValueAnimator.ofFloat(0, 1); anim.setDuration(8000); anim.setRepeatMode(ValueAnimator.REVERSE); anim.setRepeatCount(ValueAnimator.INFINITE); anim.setInterpolator(new LinearInterpolator()); anim.addUpdateListener(animation -> { float old = progress; progress = (float) animation.getAnimatedValue(); if (progress > old) positive = 1; if (progress < old) positive = -1; postInvalidate(); }); anim.start(); } @Override protected void onDraw(Canvas canvas) { //画波浪路径 int offsetX = (getMeasuredWidth() - WAVE_LENGTH) / 2; path.reset(); path.moveTo(offsetX, getMeasuredHeight() / 2); path.rQuadTo(WAVE_LENGTH / 4, 80, WAVE_LENGTH / 2, 0); path.rQuadTo(WAVE_LENGTH / 4, -80, WAVE_LENGTH / 2, 0); canvas.drawPath(path, paint); //测量路径总长度 pathMeasure = new PathMeasure(path, false); float length = pathMeasure.getLength(); //绘制对应位置的图片 matrix.reset(); pathMeasure.getMatrix(length * progress, matrix, PathMeasure.TANGENT_MATRIX_FLAG | PathMeasure.POSITION_MATRIX_FLAG); matrix.preTranslate(0, -bitmap.getHeight()); matrix.preScale(positive, 1); canvas.drawBitmap(bitmap, matrix, paint); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (anim.isPaused()) anim.resume(); else anim.pause(); } return super.onTouchEvent(event); } } 
关注
打赏
1688896170
查看更多评论

暂无认证

  • 5浏览

    0关注

    115984博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.0559s