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

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

   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);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值