android 自定义水波纹点击效果Button

welcome

效果

android 自定义水波纹点击效果Button;

技术基础思路

  • 自定义 Button
  • 自定义 Drawable

项目源码

点击查看详情

自定义button

其实这只是一些说法
自定义button,我们只需要将子类继承 button

public class AnimationButton extends Button {

    public AnimationButton(Context context) {
        super(context);
        initFunction(context, null, 0);
    }
    public AnimationButton(Context context, AttributeSet attrs) {

        super(context, attrs);

        initFunction(context, attrs, 0);

    }

    public AnimationButton(Context context, AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

        initFunction(context, attrs, defStyleAttr);

    }

    @Override

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

        super.onSizeChanged(w, h, oldw, oldh);

    }

    //初始化操作方法
    private void initFunction(Context context, AttributeSet attrs, int defStyleAttr) {

    //获取自定义属性
        if (attrs != null) {
             TypedArray typedArray =context.obtainStyledAttributes(attrs,R.styleable.AnimationButton);         

        }

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
    //验证 drawable
    @Override
    protected boolean verifyDrawable(Drawable who) {
        return who == mDrawable || super.verifyDrawable(who);
    }


    //触摸事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }
}

上述只是开发一个自定义View常用的思路

自定义 drawable


public class AnimationButtonDrawable extends Drawable {

    //默认 透明度
    private int mAlpha = 255;
    //默认画笔
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    //默认颜色
    private int mColor = 0;
    //绘制的区域
    private int mWidth, mHeight;
    //波纹圆形的 圆心与半径
    private float mCirculX, mCirculY, mCirculRadus;
    private Handler mHandler = new Handler(Looper.getMainLooper());



    private int mBackGroundNormalColor = Color.parseColor("#ffffff");
    //背景颜色
    private int mBackGroundColor = mBackGroundNormalColor;

    //背景矩形
    private RectF mBackGroundRect;
    private float rx, ry;

    //点击圆形颜色
    private int mAnimationCircleColor = Color.BLUE;
    //点击 按钮 down 颜色
    private int mBackGroundDownColor = Color.GRAY;



    public AnimationButtonDrawable() {
        //设置抗锯齿
        this.mPaint.setAntiAlias(true);
        //设置防抖动
        this.mPaint.setDither(true);
    }

    //绘制功能
    @Override
    public void draw(Canvas canvas) {

    }

    @Override
    public int getAlpha() {
        return mAlpha;
    }
    //设置透明度
    @Override
    public void setAlpha(int alpha) {
        //设置 drawable的透明度
        mAlpha = alpha;
        onColorOrAlphaChange();
    }

    //设置颜色滤镜
    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        if (mPaint.getColorFilter() != colorFilter) {
            mPaint.setColorFilter(colorFilter);
        }
    }

    //确认drawable是否有透明度
    @Override
    public int getOpacity() {
        int alpha = mPaint.getAlpha();
        if (alpha == 255) {
            //不透明
            return PixelFormat.OPAQUE;
        } else if (alpha == 0) {
            //全透明
            return PixelFormat.TRANSPARENT;
        } else {
            //半透明
            return PixelFormat.TRANSLUCENT;
        }
    }
    public void onColorOrAlphaChange() {
        mPaint.setColor(mColor);
        //获取画笔透明度
        if (mAlpha != 255) {
            int paintAlpha = mPaint.getAlpha();
            int realAppha = (int) (paintAlpha * (mAlpha / 255f));
            mPaint.setAlpha(realAppha);
        }
    }
}
  • 在这里,我们定义实现了一个基本的drawble AnimationButtonDrawable
  • 一个button ,要初始化使用的变量有

    有正常显示的背景颜色,
    有按下的背景颜色,
    当点击抬起时,绘制波纹的颜色,
    绘制波纹的位置与半径
  • 最重要的步骤是在draw方法中
    通过方法
    canvas.drawRoundRect(mBackGroundRect, rx, ry, mPaint);
    来绘制圆角矩形背景

    通过方法
    canvas.drawCircle(mCirculX, mCirculY, mCirculRadus, mPaint);
    来绘制点击后抬起的圆角矩形

    通过设置模式来解决边框圆角被覆盖问题
    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));

    完整的draw方法

//绘制功能
@Override
public void draw(Canvas canvas) {

    //绘制区域
    int canvasWidth = canvas.getWidth();
    int canvasHeight = canvas.getHeight();
    //新建图层
    int layerId = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG);
    mPaint.setColor(mBackGroundColor);

    //绘制背景 圆角矩形
    if (mBackGroundRect != null) {  
        canvas.drawRoundRect(mBackGroundRect, rx, ry, mPaint);
    }
    //设置图层重叠模式
    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
    mPaint.setColor(mAnimationCircleColor);
    //绘制圆形波纹
    canvas.drawCircle(mCirculX, mCirculY, mCirculRadus, mPaint);
    //最后将画笔去除Xfermode
    mPaint.setXfermode(null);
    canvas.restoreToCount(layerId);
}

button 与 drawable结合

在button中,当button创建的时候,我们创建drawable,

mDrawable = new AnimationButtonDrawable();

然后在button的ondraw方法中,使用drawable的draw方法,这样就通过 canvas 画布将两者关联起来了

@Override
protected void onDraw(Canvas canvas) {
    mDrawable.draw(canvas);
    super.onDraw(canvas);
}

设置点击时的button背景颜色

在button中的onTouchEvent方法,监听事件的发生,并将事件传入到drawable中


@Override
public boolean onTouchEvent(MotionEvent event) {
    //设置事件
    mDrawable.setTouchEvent(event);
    return super.onTouchEvent(event);
}

在drawable中的setTouchEvent方法中进行事件处理


public void setTouchEvent(MotionEvent event) {
    //刷新
    invalidateSelf();
    //判断点击操作
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            onTouchDown(event.getX(), event.getY());
            break;
        case MotionEvent.ACTION_MOVE:
            onTouchMove(event.getX(), event.getY());
            break;
        case MotionEvent.ACTION_UP:
            onTouchUp(event.getX(), event.getY());
            break;
        case MotionEvent.ACTION_CANCEL:
            onTouchCancel(event.getX(), event.getY());
            break;
    }
}

在ontouchDown方法, 我们更新绘制圆角矩形的颜色为按下时的颜色,并在onTouchUp方法中恢复我们正常情况下显示的背景颜色,就可以达到button点击选择器的风格

在ontouchDown方法中,我们可以开启一个异步任务,在一定的时间内不断的绘制不同半径的圆 叠加在之前绘制好的矩形背景上面,就可以在视觉方面达到一种波纹效果,

在这里 绘制不大小的圆形,是通过 不断改变绘制半径来达到这个效果的

private Runnable mRunnable = new Runnable() {
    @Override
    public void run() {
        invalidateSelf();
        if (mCirculRadus <= mWidth) {
            isRun = true;
            mCirculRadus += 18;
            mHandler.postDelayed(mRunnable, 2);
        } else {
            isRun = false;
            mCirculX = 0;
            mCirculY = 0;
            mCirculRadus = 0;
        }
    }
};
上一篇:Linux 的目录处理命令:mkdir


下一篇:android自定义局部透明遮罩-新手引导说明