天天看点

Android自定义View——贝塞尔曲线实现水波纹效果

效果图

Android自定义View——贝塞尔曲线实现水波纹效果

贝塞尔曲线

我们使用到的是Path类的quadTo(x1, y1, x2, y2)方法,属于二阶贝塞尔曲线,使用一张图来展示二阶贝塞尔曲线,这里的(x1,y1)是控制点,(x2,y2)是终止点,起始点默认是Path的起始点(0,0)

Android自定义View——贝塞尔曲线实现水波纹效果

原理分析

1、通过for循环画出两个波纹,需要波纹的-mWL点、-3/4 * mWL点、-1/2 * mWL、-1/4 * mWL四个点,通过path的quadTo画出

2、接着通过ValueAnimator对offset递增,实现平移效果,并无限重复

Android自定义View——贝塞尔曲线实现水波纹效果

实现一次循环波纹,红点为贝塞尔坐标:

Android自定义View——贝塞尔曲线实现水波纹效果

实现无限次循环波纹:

Android自定义View——贝塞尔曲线实现水波纹效果

接下来在波纹下方的空白处画上一个矩形:

Android自定义View——贝塞尔曲线实现水波纹效果

实现步骤

1、初始化变量

//波浪画笔
private Paint mPaint;
//测试红点画笔
private Paint mCyclePaint;

//波浪Path类
private Path mPath;
//一个波浪长度
private int mWaveLength = ;
//波纹个数
private int mWaveCount;
//平移偏移量
private int mOffset;
//波纹的中间轴
private int mCenterY;

//屏幕高度
private int mScreenHeight;
//屏幕宽度
private int mScreenWidth;
           

2、初始化画笔

public WaveView(Context context, AttributeSet attrs) {
    super(context, attrs);
    mPath = new Path();
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setColor(Color.LTGRAY);
    mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    setOnClickListener(this);
    //用来绘制测试红点
    mCyclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mCyclePaint.setColor(Color.RED);
    mCyclePaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
           

3、获取宽和高

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mScreenHeight = h;
    mScreenWidth = w;
    //加1.5:至少保证波纹有2个,至少2个才能实现平移效果
    mWaveCount = (int) Math.round(mScreenWidth / mWaveLength + );
    mCenterY = mScreenHeight / ;
}
           

4、绘制水波纹

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPath.reset();
    //移到屏幕外最左边
    mPath.moveTo(-mWaveLength + mOffset, mCenterY);
    for (int i = ; i < mWaveCount; i++) {
        //正弦曲线
        mPath.quadTo((-mWaveLength *  / ) + (i * mWaveLength) + mOffset, mCenterY + , (-mWaveLength / ) + (i * mWaveLength) + mOffset, mCenterY);
        mPath.quadTo((-mWaveLength / ) + (i * mWaveLength) + mOffset, mCenterY - , i * mWaveLength + mOffset, mCenterY);
        //贝塞尔坐标,测试红点
        canvas.drawCircle((-mWaveLength *  / ) + (i * mWaveLength) + mOffset, mCenterY + , , mCyclePaint);
        canvas.drawCircle((-mWaveLength / ) + (i * mWaveLength) + mOffset, mCenterY, , mCyclePaint);
        canvas.drawCircle((-mWaveLength / ) + (i * mWaveLength) + mOffset, mCenterY - , , mCyclePaint);
        canvas.drawCircle(i * mWaveLength + mOffset, mCenterY, , mCyclePaint);
    }
    //填充矩形
    mPath.lineTo(mScreenWidth, mScreenHeight);
    mPath.lineTo(, mScreenHeight);
    mPath.close();
    canvas.drawPath(mPath, mPaint);
}
           

5、实现平移效果

@Override
public void onClick(View view) {
    ValueAnimator animator = ValueAnimator.ofInt(, mWaveLength);
    animator.setDuration();
    animator.setRepeatCount(ValueAnimator.INFINITE);
    animator.setInterpolator(new LinearInterpolator());
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mOffset = (int) animation.getAnimatedValue();
            postInvalidate();
        }
    });
    animator.start();
}
           

6、源码下载

水波纹View下载