小动画之“波浪动画”(二阶贝塞尔曲线)

@[TOC](二阶贝塞尔曲线 rQuadTo() 函数实现波浪动画)

小动画之“波浪动画”(二阶贝塞尔曲线)_第1张图片


上篇博客 ”小动画之“绘画板”“ 中讲述了 二阶贝塞尔曲线以及,quadTo() 函数;本文将实现上图动画。


1. rQuadTo() 函数

  1. 函数

    publiC void rQuadTo(float dxl , float dyl, float dx2, float dy2);
    
  2. 参数 - 这4 个参数都是 相对值,即相对上一个终点的位移值。

    • dxl : 控制点x 坐标,相对上一个终点 x 坐标的位移坐标。可为负值,正值表示相加,负值表示相减。

    • dyl :控制点 y 坐标,相对上一个终点 y 坐标的位移坐标。可为负值,正值表示相加,负值表示相减。

    • dx2 : 终点 x 坐标,相对上一个终点x 坐标的位移值。可为负值,正值表示相加,负值表示相减。

    • d y2 : 终点y 坐标,相对上一个终点y 坐标的位移值。可为负值,正值表示相加, 负值表示相减。


2. 原理与代码实现

2.1 实现全屏波纹

  1. 在构造函数中,初始化一些必要的变量。

    public class AnimWaveView extends View {
    
        private Paint mPaint;
        private Paint mCirPaint;//绘制 外层圆形
        private Path mPath;
        private int mWaveLength = 800;//单个波纹长度(水平方向)
        private int dx;//波纹水平移动距离
        private int originY = 850;//波纹的原始Y坐标
    
        public AnimWaveView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
    
            mPath = new Path();
            mPaint = new Paint();
            mPaint.setStyle(Paint.Style.FILL);//波纹设置为填充模式。
            mPaint.setColor(0XFF3DDC84);
    
            mCirPaint = new Paint();
            mCirPaint.setStyle(Paint.Style.STROKE);//外层圆设置为圈圈
            mCirPaint.setStrokeWidth(5);
            mCirPaint.setColor(0XFF3DDC84);
    
            setLayerType(View.LAYER_TYPE_SOFTWARE , null);
            startAnim();//开启波纹动画
        }
    }
    
  2. 在 onDraw() 函数中整屏画满波形

    @Override
    protected void onDraw(Canvas canvas) {
    
        //剪裁画布,让动画只出现在圆形内,
        Path cirPath = new Path();
        cirPath.addCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, Path.Direction.CW);
        canvas.clipPath(cirPath);
        
        super.onDraw(canvas);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, mCirPaint);
        mPath.reset();
        
        int halfWaveLength = mWaveLength / 2;//这里为什么是一半?请参考上篇”绘画版“博文中 4.2 节
        mPath.moveTo(-mWaveLength + dx, originY);
        for (int i = -mWaveLength; i <= getWidth() + mWaveLength; i += mWaveLength) {
            mPath.rQuadTo(halfWaveLength / 2, -100, halfWaveLength, 0);
            mPath.rQuadTo(halfWaveLength / 2, 100, halfWaveLength, 0);
        }
        
        mPath.lineTo(getWidth(), getHeight());//闭合路径,否则将无法绘制波浪颜色
        mPath.lineTo(0, getHeight());
        mPath.close();
        
        canvas.drawPath(mPath, mPaint);
        if (originY <= -10) {
            originY = 850;//重置波纹的纵坐标
        }
    }
    

2.2 实现动画移动

  1. 在调用 path.moveTo() 函数的时候,将起始点向右移动即可实现。只要移动一个波长的长度,波纹就会重合,就可以实现无限循环。
    private void startAnim() {
        ValueAnimator animator = ValueAnimator.ofInt(0, mWaveLength);
        animator.setDuration(1500);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setInterpolator(new LinearInterpolator());
        
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                dx = (int) animation.getAnimatedValue();
                originY -= (2 * dx / mWaveLength);//Y坐标也随着X增长
                postInvalidate();
            }
        });
        animator.start();
    }
    

2.3 布局

  1. 采用帧布局,将两者重叠

    <FrameLayout
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center">
        
        <com.example.customview.wave_anim.AnimWaveView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#fff"
            android:layout_gravity="center" />
            
        <ImageView
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_gravity="center"
            android:background="@drawable/ic_launcher" />
    

3. 注意

  1. 难点在于对新知识的不熟悉;如何将波纹显示在圆圈里?

    应该用到画布剪裁,clipParh() 方法,而不是单纯的重绘圆形 canvas;


声明:本文整理自《《Android自定义控件开发入门与实战》_启舰》;

你可能感兴趣的:(Android学习总结)