zoukankan      html  css  js  c++  java
  • 利用pathMeasure实现路径动画

    package com.loaderman.customviewdemo;
    
    import android.animation.ValueAnimator;
    import android.content.Context;
    import android.graphics.*;
    import android.util.AttributeSet;
    import android.view.View;
    
    
    public class GetSegmentView extends View {
    
        private Path mCirclePath, mDstPath;
        private Paint mPaint;
        private PathMeasure mPathMeasure;
        private Float mCurAnimValue;
    
        public GetSegmentView(Context context, AttributeSet attrs) {
            super(context, attrs);
            setLayerType(LAYER_TYPE_SOFTWARE, null);
    
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(4);
            mPaint.setColor(Color.BLACK);
    
            mDstPath = new Path();
            mCirclePath = new Path();
            mCirclePath.addCircle(100, 100, 50, Path.Direction.CW);
    
            mPathMeasure = new PathMeasure(mCirclePath, true);
    
            ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
            animator.setRepeatCount(ValueAnimator.INFINITE);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurAnimValue = (Float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            animator.setDuration(2000);
            animator.start();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            float length = mPathMeasure.getLength();
            float stop = length * mCurAnimValue;
            float start = (float) (stop - ((0.5 - Math.abs(mCurAnimValue - 0.5)) * length));
            mDstPath.reset();
            canvas.drawColor(Color.WHITE);
            mPathMeasure.getSegment(start, stop, mDstPath, true);//用于截取整个path中某个片段,通过参数startD和stopD来控制截取的长度,并将截取后的path保存到参数dst中,最后一个参数表示起始点是否使用moveTo将路径的新起始点移到结果path的起始点中,通常设置为true
    
    //        mPathMeasure.getSegment(0, stop, mDstPath, true);
            canvas.drawPath(mDstPath, mPaint);
        }
    }
    package com.loaderman.customviewdemo;
    
    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;
    
    
    public class AliPayView extends View {
        private Path mCirclePath, mDstPath;
        private Paint mPaint;
        private PathMeasure mPathMeasure;
        private Float mCurAnimValue;
        private int mCentX = 100;
        private int mCentY = 100;
        private int mRadius = 50;
    
        public AliPayView(Context context, AttributeSet attrs) {
            super(context, attrs);
            setLayerType(LAYER_TYPE_SOFTWARE, null);
    
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(4);
            mPaint.setColor(Color.BLACK);
    
            mDstPath = new Path();
            mCirclePath = new Path();
    
            mCirclePath.addCircle(mCentX, mCentY, mRadius, Path.Direction.CW);
    
            mCirclePath.moveTo(mCentX - mRadius / 2, mCentY);
            mCirclePath.lineTo(mCentX, mCentY + mRadius / 2);
            mCirclePath.lineTo(mCentX + mRadius / 2, mCentY - mRadius / 3);
    
            mPathMeasure = new PathMeasure(mCirclePath, false);
    
            ValueAnimator animator = ValueAnimator.ofFloat(0, 2);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurAnimValue = (Float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            animator.setDuration(4000);
            animator.start();
        }
    
        boolean mNext = false;
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawColor(Color.WHITE);
    
            if (mCurAnimValue < 1) {
                float stop = mPathMeasure.getLength() * mCurAnimValue;
                mPathMeasure.getSegment(0, stop, mDstPath, true);
            } else {
                if (!mNext) {
                    mNext = true;
                    mPathMeasure.getSegment(0, mPathMeasure.getLength(), mDstPath, true);
                    mPathMeasure.nextContour();  //跳转到下一条曲线函数
                }
                float stop = mPathMeasure.getLength() * (mCurAnimValue - 1);
                mPathMeasure.getSegment(0, stop, mDstPath, true);
            }
            canvas.drawPath(mDstPath, mPaint);
        }
    }
    package com.loaderman.customviewdemo;
    
    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.View;
    
    
    public class GetPosTanView extends View {
        private Path mCirclePath, mDstPath;
        private Paint mPaint;
        private PathMeasure mPathMeasure;
        private Float mCurAnimValue;
        private Bitmap mArrawBmp;
        private float[] pos = new float[2];
        private float[] tan = new float[2];
    
        public GetPosTanView(Context context, AttributeSet attrs) {
            super(context, attrs);
            setLayerType(LAYER_TYPE_SOFTWARE, null);
            mArrawBmp = BitmapFactory.decodeResource(getResources(), R.drawable.arraw);
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(4);
            mPaint.setColor(Color.BLACK);
    
            mDstPath = new Path();
            mCirclePath = new Path();
            mCirclePath.addCircle(100, 100, 50, Path.Direction.CW);
    
            mPathMeasure = new PathMeasure(mCirclePath, true);//true计算的path的闭合长度,false则测量当前path状态长度
    
            ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
            animator.setRepeatCount(ValueAnimator.INFINITE);//无限循环
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurAnimValue = (Float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            animator.setDuration(2000);
            animator.start();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            canvas.drawColor(Color.WHITE);
            float length = mPathMeasure.getLength();  //计算路径长度
            float stop = length * mCurAnimValue;
            mDstPath.reset();
    
            mPathMeasure.getSegment(0, stop, mDstPath, true);
            canvas.drawPath(mDstPath, mPaint);
    
    
            /**
             * 箭头旋转、位移实现方式一:
             */
    
            //计算方位角
    //        mPathMeasure.getPosTan(stop, pos, tan);//用于得到路径上某一长度的位置,以及位置的证正切值
    //        float degrees = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI);
    //        Matrix matrix = new Matrix();
    //        matrix.postRotate(degrees, mArrawBmp.getWidth() / 2, mArrawBmp.getHeight() / 2);
    //        matrix.postTranslate(pos[0] - mArrawBmp.getWidth() / 2, pos[1] - mArrawBmp.getHeight() / 2);
    
            /**
             * 箭头旋转、位移实现方式一:
             */
            Matrix matrix = new Matrix();
            mPathMeasure.getMatrix(stop, matrix, PathMeasure.POSITION_MATRIX_FLAG | PathMeasure.TANGENT_MATRIX_FLAG);//用于的到路径上某一长度的位置以及该位置的正切值的矩阵
            matrix.preTranslate(-mArrawBmp.getWidth() / 2, -mArrawBmp.getHeight() / 2);
            canvas.drawBitmap(mArrawBmp, matrix, mPaint);
        }
    
    
    }
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    
    
        <com.loaderman.customviewdemo.GetSegmentView
            android:layout_width="match_parent"
            android:layout_height="80dp"/>
        <com.loaderman.customviewdemo.AliPayView
            android:layout_width="match_parent"
            android:layout_height="80dp"/>
        <com.loaderman.customviewdemo.GetPosTanView
            android:layout_width="match_parent"
            android:layout_height="150dp"/>
    </LinearLayout>

    效果

  • 相关阅读:
    angularjs 学习教程
    Mac下的开发工具
    国双前端笔试题-2016年07月08日
    css3 box-sizing属性
    .NET中制做对象的副本(一)
    Nginx限制IP访问及获取客户端realip实战
    Saltstack实战之无master和多master
    Saltstack之job管理和runner
    Python之异常处理
    Python内置函数之isinstance,issubclass
  • 原文地址:https://www.cnblogs.com/loaderman/p/10208246.html
Copyright © 2011-2022 走看看