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

在这里插入图片描述


上篇博客 ”小动画之“绘画板”“ 中讲述了 二阶贝塞尔曲线以及,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自定义控件开发入门与实战》_启舰》;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liusaisaiV1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值