Path绘制动态的贝塞尔曲线、PathMeasure来绘制path动画

来源:互联网 发布:科比本赛季数据 编辑:程序博客网 时间:2024/05/17 02:17

上一篇的波浪曲线是左右重复平移,这次是每一帧绘制一条线,组成上下浮动的曲线,下面是效果图
这里写图片描述

   public WaveView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        paint = new Paint(Paint.ANTI_ALIAS_FLAG);        paint.setStrokeWidth(6);        paint.setColor(Color.BLUE);        paint.setStyle(Paint.Style.STROKE);        path = new Path();
  @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawCircle(200, 200, 90, paint);        path.reset();        path.moveTo(waveLength / 2, startY);        path.rQuadTo(waveLength / 2, -waveHeight, waveLength, 0);        path.rQuadTo(waveLength / 2, waveHeight, waveLength, 0);        canvas.drawPath(path, paint);

下面是通过属性动画来改变贝塞尔控制点

 protected void startAnimation() {        //通过属性动画计算高度        final ValueAnimator animator = ValueAnimator.ofInt(-waveHeight, waveHeight);        animator.setDuration(4000);        animator.setRepeatCount(ValueAnimator.INFINITE);        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                waveHeight = (int) animation.getAnimatedValue();                postInvalidateDelayed(1);            }        });        animator.setRepeatMode(ValueAnimator.REVERSE);        animator.start();    }

path的曲线动画,下面是效果图
这里写图片描述

//全部代码如下:    private PathMeasure pathM;    private Bitmap bitmap;    private int bitHeight;    private int bitWidth;    private Rect rect;    private Matrix matrix;    public WaveView(Context context) {        this(context, null);    }    public WaveView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        paint = new Paint(Paint.ANTI_ALIAS_FLAG);        paint.setStrokeWidth(6);        paint.setColor(Color.BLUE);        paint.setStyle(Paint.Style.STROKE);        path = new Path();        //来个path计算器        pathM = new PathMeasure();        bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_music);        bitHeight = bitmap.getHeight();        bitWidth = bitmap.getWidth();    }    private Paint paint;//定义画笔    private int waveLength = 200;//定义波长度    private Path path;//曲线路径    private int waveHeight = 120;//定义波的高度    private int startY = 500;//起点的Y坐标    private static String TAG = "test";    private float fraction = 0.0f;    private float[] position = new float[2];    private float[] tange = new float[2];    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawCircle(200, 200, 90, paint);        path.reset();        path.moveTo(waveLength / 2, startY);        path.rQuadTo(waveLength / 2, -waveHeight, waveLength, 0);        path.rQuadTo(waveLength / 2, waveHeight, waveLength, 0);        canvas.drawPath(path, paint);        pathM.setPath(path, false);        float length = pathM.getLength();        Log.i(TAG, "WaveView: 长度==" + length);        boolean flag = pathM.getPosTan(fraction * length, position, tange);        if (flag) {            //开始绘制运行轨迹            canvas.drawBitmap(bitmap, position[0] - bitWidth, position[1] - bitHeight, paint);        }    }    protected void computePercent() {        ValueAnimator animator = ValueAnimator.ofFloat(0, 1.0f);        animator.setDuration(4000);        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                fraction = (float) animation.getAnimatedValue();                Log.i(TAG, "onAnimationUpdate: 百分比==" + fraction);                postInvalidateDelayed(5);            }        });        animator.start();    }

上面有点缺陷就是“音乐符号”的运动角度没有设置和调整,调整后的效果如右边所示:这里写图片描述

 public WaveView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        paint = new Paint(Paint.ANTI_ALIAS_FLAG);        paint.setStrokeWidth(6);        paint.setColor(Color.BLUE);        paint.setStyle(Paint.Style.STROKE);        path = new Path();        //新增代码。来个path计算器        pathM = new PathMeasure();        bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_music);        bitHeight = bitmap.getHeight();        bitWidth = bitmap.getWidth();        matrix=new Matrix();    }    private Paint paint;//定义画笔    private int waveLength = 200;//定义波长度    private Path path;//曲线路径    private int waveHeight = 120;//定义波的高度    private int startY = 500;//起点的Y坐标    private static String TAG = "test";    private float fraction = 0.0f;    private float[] position = new float[2];    private float[] tange = new float[2];    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawCircle(200, 200, 90, paint);        path.reset();        path.moveTo(waveLength / 2, startY);        path.rQuadTo(waveLength / 2, -waveHeight, waveLength, 0);        path.rQuadTo(waveLength / 2, waveHeight, waveLength, 0);        canvas.drawPath(path, paint);        pathM.setPath(path, false);        float length = pathM.getLength();        Log.i(TAG, "WaveView: 长度==" + length);        boolean flag = pathM.getPosTan(fraction * length, position, tange);        if (flag) {            //开始绘制运行轨迹//            canvas.drawBitmap(bitmap, position[0] - bitWidth, position[1] - bitHeight, paint);            matrix.reset();            float degree = (float) (Math.atan2(tange[1], tange[0])*180f/Math.PI);            matrix.postRotate(degree,bitmap.getWidth()/2,bitmap.getHeight()/2);            matrix.postTranslate(position[0]-bitmap.getWidth()/2,position[1]-bitmap.getHeight()/2);            canvas.drawBitmap(bitmap,matrix,paint);        }    }    protected void computePercent() {        ValueAnimator animator = ValueAnimator.ofFloat(0, 1.0f);        animator.setDuration(4000);        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                fraction = (float) animation.getAnimatedValue();                Log.i(TAG, "onAnimationUpdate: 百分比==" + fraction);                postInvalidateDelayed(5);            }        });        animator.start();    }

总结:还有一种比较好的测量 方式,直接返回matrix,这个matrix里面包含了delt x和y,以及tang角度。

        boolean flag = pathM.getMatrix(fraction * length, matrix, PathMeasure.POSITION_MATRIX_FLAG | PathMeasure.TANGENT_MATRIX_FLAG);        if (flag) {            canvas.drawBitmap(bitmap, matrix, paint);        }

新测量方式的源码截取和解释如下

  /**     * Pins distance to 0 <= distance <= getLength(), and then computes the     * corresponding matrix. Returns false if there is no path, or a zero-length     * path was specified, in which case matrix is unchanged.     *     * @param distance The distance along the associated path     * @param matrix Allocated by the caller, this is set to the transformation     *        associated with the position and tangent at the specified distance     * @param flags Specified what aspects should be returned in the matrix.     */    public boolean getMatrix(float distance, Matrix matrix, int flags) {        return native_getMatrix(native_instance, distance, matrix.native_instance, flags);    }