Android圆形水波纹WaveLoading动画

本文介绍如何使用Android Canvas和Paint的PorterDuffXfermode实现动态水波纹效果,通过调整贝塞尔曲线参数模拟真实水波扩散过程。

效果图:

这里写图片描述

一、 介绍Paint.setXfermode() 以及PorterDuffXfermode

public class WaveView extends View {

    private Paint mWavePaint;

    private Paint mCirclePaint;
    private Canvas mCanvas;
    private Bitmap mBitmap;
    private int mWidth;
    private int mHeight;
    private PorterDuffXfermode mMode = new PorterDuffXfermode(PorterDuff.Mode.XOR);//设置mode 为XOR


    public WaveView(Context context) {
        super(context, null);
    }

    public WaveView(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        mWavePaint = new Paint();
        mWavePaint.setColor(Color.parseColor("#33b5e5"));
        mCirclePaint = new Paint();
        mCirclePaint.setColor(Color.parseColor("#99cc00"));
        mBitmap = Bitmap.createBitmap(500,500, Bitmap.Config.ARGB_8888); //生成一个bitmap
        mCanvas = new Canvas(mBitmap);
    }

    public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode == MeasureSpec.EXACTLY) {
            mWidth = widthSize;
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            mHeight = heightSize;
        }
        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mCanvas.drawCircle(100,100,100,mCirclePaint);

        mCanvas.drawRect(100,100,300,300,mWavePaint);
        canvas.drawBitmap(mBitmap,200,200,null);
        super.onDraw(canvas);
    }
}

可以看到 是我们现在自己的画布上铺了一个bitmap(这里可以理解canvas为桌子 bitmap为画纸,我们在bimap上画画), 然后在bitmap上画了 一个圆,和一个矩形。最后把我们的mBitmap画到系统的画布上(显示到屏幕上),得到了以下效果。

这里写图片描述

然后我们用setXfermode()方法给他设置一个mode,这里设置SRC_IN。效果如下:

这里写图片描述

总结各个模式如了下图:

我们要实现的是一个圆形的水波纹那种loadingview。。首要就是实现这个水波纹。这时候贝塞尔曲线就派上用场了。这里采用三阶贝塞尔, 不停地改变X 模拟水波效果。

public class WaveLoadingView extends View {
    private final Paint mSRCPaint;

    private Paint mPaint;
    private Paint mTextPaint;
    private Canvas mCanvas;
    private Bitmap mBitmap;
    private int y;
    private int x;

    private Path mPath;
    private boolean isLeft;
    private int mWidth;
    private int mHeight;
    private int mPercent;
    private PorterDuffXfermode mMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);

    public WaveLoadingView(Context context) {
        this(context, null);
    }

    public WaveLoadingView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WaveLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setStrokeWidth(10);
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.parseColor("#8800ff66"));

        mPath = new Path();
        mSRCPaint = new Paint();
        mSRCPaint.setAntiAlias(true);
        mSRCPaint.setColor(Color.parseColor("#88dddddd"));
        mBitmap = Bitmap.createBitmap(getResources().getDimensionPixelSize(R.dimen.bg_size),
                getResources().getDimensionPixelSize(R.dimen.bg_size), Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode == MeasureSpec.EXACTLY) {
            mWidth = widthSize;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            mHeight = heightSize;
        }

        y = mHeight;
        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (x > 100) {
            isLeft = true;
        } else if (x < 0) {
            isLeft = false;
        }

        if (isLeft) {
            x = x - 2;
        } else {
            x = x + 2;
        }
        mPath.reset();
        if (mPercent != 0) {
            y = (int) ((1 - mPercent /100f) *mHeight);
            mPath.moveTo(0, y);
            mPath.cubicTo(100 + x * 2, 50 + y, 100 + x * 2, y - 50, mWidth, y);
            mPath.lineTo(mWidth, mHeight);
            mPath.lineTo(0, mHeight);
            mPath.close();
        }
        //清除掉图像 不然path会重叠
        mBitmap.eraseColor(Color.parseColor("#00000000"));
        mCanvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mSRCPaint);

        mPaint.setXfermode(mMode);
        mCanvas.drawPath(mPath, mPaint);
        mPaint.setXfermode(null);

        canvas.drawBitmap(mBitmap, 0, 0, null);

        mTextPaint.setTextSize(80);
        float strLen = mTextPaint.measureText(mPercent + "");
        canvas.drawText(mPercent + "", mWidth / 2 - strLen / 2, mHeight / 2+15, mTextPaint);
        mTextPaint.setTextSize(40);
        canvas.drawText("%", mWidth / 2 + 50, mHeight / 2 - 20, mTextPaint);

        postInvalidateDelayed(10);
    }


    public void setPercent(int percent){
        mPercent = percent;
    }

}

效果如下:
这里写图片描述

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值