1. 程式人生 > >android 自定義水波紋點選效果Button

android 自定義水波紋點選效果Button

welcome

效果

;

技術基礎思路

  • 自定義 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;
        }
    }
};