美文网首页
PathMeasure基本使用

PathMeasure基本使用

作者: youtianlong123 | 来源:发表于2017-06-09 15:42 被阅读0次

    PathMeasure从名字就可以看出,这个类应该关联一个path类对象。它是对它关联path对象的进一步测量。所以PathMeasure与Path是一一对应的,一个PathMeasure对象如果没有与他关联的Path对象,那么这个PathMeasure也就没什么存在的意义了。它提供了测量path长度,返回一个点的坐标和正切值等方法。


    PathMeasure提供的方法
    • 构造函数(Constructors)

    • 无参构造函数:仅仅是构造了一个PathMeasure对象,并没有关联任何path。要想使用它可以调用setPath传入想要关联的path。
    • 有参构造函数:接收一个path对象与之关联,这个path对象就是我们想要测量的实体。第二个boolean类型的forceClosed的意义。如果传入的是true,那么即使传入的path不是闭合的,那么也强制认为它的闭合的。如果是false,就不会又任何变化。一般使用的时候都会传入false。
    • 公共方法

    • getLength:返回关联path当前轮廓的长度,如果没有关联path,将会返回0;
    • getMatrix:传入的distance要大于0,并且小于path当前轮廓的长度。它会计算distance在Path上对应的点的信息,并将信息封装到传入的martrix中。通过返回的boolean值可以判断计算是否成功。
    • getPosTan:传入的distance要大于0,并且小于path当前轮廓的长度。它会计算distance在Path上对应的点的信息,并将信息封装到float[] pos和float[] tan中,他们分别是一个长度为2的数组,数组中index=0是x方向上的信息,index=1是y方向上的信息。通过返回的boolean值可以判断计算是否成功。
    • getSegment:startD和stopD分别是起始距离和终止距离,此方法会裁剪取出他们中间的path放到dst中。startD和stopD都应该是合法的值,否则返回false。裁剪出来的path长度为0也会返回false,如果是正常的情况,就会返回true。startWithMoveTo为true表示截取到的path的第一个点不变。如果为false,截取到的path的起点会连接到dst之前到的最后一个点。
    • isClosed:当前轮廓是否是闭合的
    • nextContour:移动到path中的下一个轮廓上
    • setPath:设置与之有关的path.第二个boolean类型的forceClosed的意义。如果传入的是true,那么即使传入的path不是闭合的,那么也强制认为它的闭合的。如果是false,就不会又任何变化。一般使用的时候都会传入false。

    方法就这么几个,而且很简单。接下来利用这几个方法,来做两个炫酷的效果。

    旋转小飞机

    小飞机沿着红圈当前点的切线方向旋转飞行
    public class PlaneView extends View{
    
        private Paint mPaint;
        private int mWidth,mHeight;
        private Path mPath;
        private Bitmap mBitmap;
        private int mBitmapWidth,mBitmapHeight;
        private Matrix mMatrix;
        private float[] pos;
        private float[] tan;
        private PathMeasure pathMeasure;
        private float totalLength,currentLength;
    
        public PlaneView(Context context) {
            this(context,null);
        }
    
        public PlaneView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public PlaneView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            pos = new float[2];
            tan = new float[2];
    
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setStrokeWidth(4);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(Color.RED);
            mPath = new Path();
            // 获取缩放的小飞机图片
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = 8;
            mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.arrow,options);
            mBitmapWidth = mBitmap.getWidth();
            mBitmapHeight = mBitmap.getHeight();
    
            mMatrix = new Matrix();
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mWidth = getWidth();
            mHeight = getHeight();
            mPath.addCircle(mWidth/2,mHeight/2,220, Path.Direction.CW);
            // 创建一个PathMeasure与Path关联
            pathMeasure = new PathMeasure(mPath,false);
            // 获取Path的总长度
            totalLength = pathMeasure.getLength();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            // 画坐标轴
            canvas.drawLine(mWidth/2,0,mWidth/2,mHeight,mPaint);
            canvas.drawLine(0,mHeight/2,mWidth,mHeight/2,mPaint);
            // 画圆圈
            canvas.drawPath(mPath,mPaint);
    
            // 获取当前点的信息
            boolean posTan = pathMeasure.getPosTan(currentLength, pos, tan);
            if (posTan){
                mMatrix.reset();
                // 计算图片要旋转的角度
                float degrees = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI);
                // 旋转图片
                mMatrix.postRotate(degrees,mBitmapWidth / 2,mBitmapHeight / 2);
                // 将图片中心绘制到当前点
                mMatrix.postTranslate(pos[0] - mBitmapWidth / 2,pos[1] - mBitmapHeight / 2);
                canvas.drawBitmap(mBitmap,mMatrix,mPaint);
                currentLength += 5;
                if (currentLength >= totalLength){
                    currentLength = 0.0f;
                }
                invalidate();
            }
        }
    }
    

    一个正在加载中的小特效

    public class CircleView extends View {
    
        private int mWidth,mHeight;
        private Path mPath,mDst;
        private Paint mPaint;
        private PathMeasure pathMeasure;
        private float animatedValue;
    
        public CircleView(Context context) {
            this(context,null);
        }
    
        public CircleView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(5);
    
            mPath = new Path();
            mDst = new Path();
            // 执行动画
            final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);
            valueAnimator.setDuration(2000);
            valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
            valueAnimator.start();
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    animatedValue = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            mWidth = getWidth();
            mHeight = getHeight();
    
            mPath.addCircle(mWidth / 2,mHeight /2,220, Path.Direction.CW);
            pathMeasure = new PathMeasure(mPath,false);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            mDst.reset();
            // 计算新path的终点位置
            float stop = pathMeasure.getLength() * animatedValue;
            // 计算新path的起点位置
            float start = (float) (stop - ((0.5 - Math.abs(animatedValue - 0.5)) * pathMeasure.getLength()));
            // 根据计算的值截取出新Path
            boolean segment = pathMeasure.getSegment(start, stop, mDst, true);
            if (segment){
                canvas.drawPath(mDst,mPaint);
            }
        }
    }
    

    小船随波逐流

    public class WaveView extends View {
    
        private static int DRAW_BOAT_OFFSET = 15;
        private Bitmap bitmap;
        private int mWaveLength;
        private Path mPath;
        private int mHeight;
        private int mWidth;
        private Paint mPaint;
        private Matrix mMatrix;
        private PathMeasure pathMeasure;
        private float animatedValue;
    
        public WaveView(Context context) {
            this(context,null);
        }
    
        public WaveView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            // 加载小船图片
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = 2;
            bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.timg, options);
    
            // 初始化需要用到的变量
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setColor(Color.argb(105,0,0,255));
            mPaint.setStyle(Paint.Style.FILL);
            mPath = new Path();
            mMatrix = new Matrix();
            pathMeasure = new PathMeasure();
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            mWidth = getWidth();
            mHeight = getHeight();
            mWaveLength = mWidth / 2;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            mPath.reset();
            // 根据动画的进行进度设置波浪形的path路径,并绘制波浪
            mPath.moveTo(-mWaveLength+(mWaveLength/2)*animatedValue,mHeight/2);
            for (int i = -mWaveLength; i < mWidth + mWaveLength; i+=mWaveLength) {
                mPath.rQuadTo(mWaveLength / 2 +(mWaveLength/2)*animatedValue,
                        60,
                        mWaveLength+(mWaveLength/2)*animatedValue,
                        0);
                mPath.rQuadTo(mWaveLength / 2 +(mWaveLength/2)*animatedValue,
                        -60,
                        mWaveLength+(mWaveLength/2)*animatedValue,
                        0);
            }
            mPath.lineTo(mWidth,mHeight);
            mPath.lineTo(0,mHeight);
            mPath.close();
            canvas.drawPath(mPath,mPaint);
    
            // 因为每次绘制的path可能都不同,所以每次都为pathMeasure设置path
            pathMeasure.setPath(mPath,false);
            // 根据动画进行的进度取出当前长度的matrix
            boolean matrix = pathMeasure.getMatrix(animatedValue * pathMeasure.getLength(), mMatrix,
                    PathMeasure.TANGENT_MATRIX_FLAG | PathMeasure.POSITION_MATRIX_FLAG);
            if (matrix){
                // 操作matrix,绘制小船
                mMatrix.preTranslate(-bitmap.getWidth() / 2,-bitmap.getHeight() + DRAW_BOAT_OFFSET);
                canvas.drawBitmap(bitmap,mMatrix,null);
            }
        }
    
        // 开启动画
        public void startAnimator(){
            ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);
            valueAnimator.setDuration(15000);
            valueAnimator.setInterpolator(new LinearInterpolator());
            valueAnimator.setRepeatCount(INFINITE);
            valueAnimator.start();
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    animatedValue = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
        }
    }
    

    相关文章

      网友评论

          本文标题:PathMeasure基本使用

          本文链接:https://www.haomeiwen.com/subject/gxgzfxtx.html