笔记:Android自定义按钮涟漪效果

来源:互联网 发布:2016年7月淘宝新政策 编辑:程序博客网 时间:2024/05/21 05:37

目标

1.创建一个类继承Button并重写onDraw方法

2.创建一个类继承Drawable,在类中实现以下目标

  • 能设定颜色,透明度
  • 点击画圆
  • 自动淡出圆的动画效果

首先创建Button类代码如下:

public class RippleButton extends android.suppert.v7.widget.AppCompatButton {    private RippleDrawable mRippleDrawable;    public RippleButton(Context context){        this(context,null);    }    public RippleButton(Context context,AttributeSet attrs){    this(context,attrs,0);      }    public RippleButton(Context context,AttributSet attrs,int defStyleAttr){        super(context,attrs,defStyleAttr);        mRippleDrawable = new RippleDrawable();    }    protected void onDraw(Canvas canvas){        super.onDraw(canvas);        mRippleDrawable.draw(canvas);    }}

创建Drawable类,实现draw方法:

public class RippleDrawable extends Drawable{    public RippleDrawable(){    }    public void draw(Canvas canvas){    }}

布局设置:
background背景图可放不可放.

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.test.android.customviewtest.MainActivity">    <com.test.android.customviewtest.RippleButton        android:layout_width="match_parent"        android:layout_height="400dp"        android:layout_centerInParent="true"        android:background="@drawable/ba"        android:gravity="center"        android:text="Ripple Button"        android:textColor="@color/colorPrimary"        /></RelativeLayout>

接下来画涟漪的圆在RippleDrawable类中:

public class RippleDrawable extends Drawable{    private int mRippleColor = 0;    private int mAlpha = 255;    private Paint mPaint = new Paint();    private float mRipplePointX, mRipplePointY;//圆心坐标    private float mRippleRadios = 0;//半径    public RippleDrawable() {        mPaint.setAntiAlias(true);//开启抗锯齿,抗平滑        mPaint.setDither(true);//开启防抖动        setRippleColor(Color.RED);//设置涟漪圆的颜色        //滤镜,可以根据需求来,也可以不设//        setColorFilter(new LightingColorFilter(0xFFFF0000,0x00330000));    }    private int mPaintAlpha = 255;    private int mBackgroundColor;    public void draw(Canvas canvas){    mPaint.setAlpha(mPaintAlpha);    canvas.drawColor(mBackgroundColor);    canvas.drawCircle(mRipplePointX,mRipplePointY,mRippleRadios,mPaint);    }    @Override    public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {        mAlpha = alpha;        onColorOrAlphaChange();    }    @Override    public int getAlpha() {        return mAlpha;    }    public void setRippleColor(int color){        mRippleColor = color;        onColorOrAlphaChange();    }    public void onColorOrAlphaChange(){        mPaint.setColor = mRippleColor;        if(mAlpha != 255){            int pAlpha = mPaint.getAlpha();            int realAlpha = (int)(pAlpha * (mAlpha/255f));            mPaint.setAlpha(realAlpha);            mPaint.getColor();        }        invalidateSelf();    }     @Override    public void setColorFilter(@Nullable ColorFilter colorFilter) {        if (mPaint.getColorFilter() != colorFilter) {            mPaint.setColorFilter(colorFilter);            invalidateSelf();        }    }    @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;        }    }}

点击事件:
RippleButtion类
圆点击事件实现刷新需要3步

public class RippleButton extends android.support.v7.widget.AppCompatButton {......public RippleButton(Context context, AttributeSet attrs, int defStyleAttr) {        ......        //1.设置刷新回调        mRippleDrawable.setCallback(this);    }    @Override    protected boolean verifyDrawable(@NonNull Drawable who) {        //2.验证drawable是否OK        return who == mRippleDrawable || super.verifyDrawable(who);    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        //3.设置drawable重绘和刷新的区域        mRippleDrawable.setBounds(0, 0, getWidth(), getHeight());    }    @Override    public boolean onTouchEvent(MotionEvent event) {        mRippleDrawable.onTouch(event);        super.onTouchEvent(event);        return true;    }}

RippleDrawable中要实现点击事件,进\退出动画

//用户是否抬起    private boolean mTouchRelease;    public void onTouch(MotionEvent event) {        //getAction()封装了点击的详细信息,是点击抬起还是按下的操作,同时包括点击的坐标信息.        //getActionMasked()仅仅只保留了点击的操作        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;        }    }    private void onTouchDown(float x, float y) {        mDonePointX = x;        mDonePointY = y;        mRippleRadios = 0;        mTouchRelease = false;        startEnterRunnable();//        mRunnable.run();    }    private void onTouchMove(float x, float y) {    }    private void onTouchUp(float x, float y) {        mTouchRelease = true;        if (mEnterDone)            startExitRunnable();    }    private void onTouchCancel(float x, float y) {        mTouchRelease = true;        if (mEnterDone)            startExitRunnable();    }    private boolean mEnterDone;    private float mEnterProgress = 0;    //动画查看器,用于实现从快到慢的效果    private Interpolator mEnterInterpolator = new DecelerateInterpolator(2);    private Runnable mRunnable = new Runnable() {        @Override        public void run() {            mEnterProgress = mEnterProgress + 0.01f;            if (mEnterProgress > 1) {                onEnterDone();                return;            }            float realProgress = mEnterInterpolator.getInterpolation(mEnterProgress);            onEnterProgress(realProgress);            scheduleSelf(this, SystemClock.currentThreadTimeMillis() + 16);        }    };    private void onEnterDone() {        mEnterDone = true;        if (mTouchRelease) {            startExitRunnable();        }    }    private void onEnterProgress(float progress) {        float maxRadius = Math.max(mCenterPointX, mCenterPointY);        mRippleRadios = getProgresValue(0f, maxRadius, progress);        mRipplePointX = getProgresValue(mDonePointX, mCenterPointX, progress);        mRipplePointY = getProgresValue(mDonePointY, mCenterPointY, progress);        int alpha = (int) getProgresValue(0, 64, progress);        mBackgroundColor = changeColorAlpha(0x00000000, alpha);        invalidateSelf();    }    //启动进入动画    private void startEnterRunnable() {        mPaintAlpha = 255;        mEnterDone = false;        mEnterProgress = 0;        unscheduleSelf(mExitRunnable);        unscheduleSelf(mRunnable);        scheduleSelf(mRunnable, SystemClock.uptimeMillis());    }    //启动退出动画    private void startExitRunnable() {        mExitProgress = 0;        unscheduleSelf(mRunnable);        unscheduleSelf(mExitRunnable);        scheduleSelf(mExitRunnable, SystemClock.uptimeMillis());    }    //退出动画进度值    private float mExitProgress = 0;    //动画查看器,用于实现从慢到快的效果    private Interpolator mExitInterpolator = new AccelerateInterpolator(2);    private Runnable mExitRunnable = new Runnable() {        @Override        public void run() {            mExitProgress = mExitProgress + 0.01f;            if (mExitProgress > 1) {                onExitDone();                return;            }            float realProgress = mExitInterpolator.getInterpolation(mExitProgress);            onExitProgress(realProgress);            scheduleSelf(this, SystemClock.currentThreadTimeMillis() + 16);        }    };    private void onExitDone() {    }    /*    退出动画刷新方法     */    private void onExitProgress(float progress) {//        float maxRadius = Math.max(mCenterPointX,mCenterPointY);//        mRippleRadios = getProgresValue(maxRadius,0f,progress);        int alpha = (int) getProgresValue(64, 0, progress);        mBackgroundColor = changeColorAlpha(0x00000000, alpha);        mPaintAlpha = (int) getProgresValue(255, 0, progress);        invalidateSelf();    }    private float getProgresValue(float start, float end, float progress) {        return start + (end - start) * progress;    }    //按下时的点    private float mDonePointX, mDonePointY;    //控件的中心点    private float mCenterPointX, mCenterPointY;    @Override    protected void onBoundsChange(Rect bounds) {        super.onBoundsChange(bounds);        mCenterPointX = bounds.centerX();        mCenterPointY = bounds.centerY();    }    private int changeColorAlpha(int color, int alpha) {        int r = (color >> 16) & 0xFF;        int g = (color >> 8) & 0xFF;        int b = (color) & 0xFF;        return (alpha << 24) | (r << 16) | (g << 8) | b;    }