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

本文介绍了如何在Android中自定义按钮以实现涟漪点击效果。通过创建继承Button的类并重写onDraw方法,以及创建继承Drawable的类来设定颜色、透明度并实现点击时画圆及淡出动画。详细步骤包括Button类的编写、Drawable类的draw方法实现、布局背景设置以及点击事件的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目标

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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值