Android Button 按钮 自制水波效果

从 5.0 开始,一些控件的点击时候默认是有水纹效果的如下图

当然了,我们这里不是将如何使用 5.0 的水波纹效果,而是将如何自己实现一个水波纹效果

自制水波纹效果

水波纹效果可以用在任何 View 上,我们这里使用 Button 来实现

一般情况下,水波纹效果都是使用两个 Paint (画笔) 来实现,一个负责绘制背景色,一个负责绘制水波纹效果

然后定时增大水波纹的半径,等达到最大的状态时重置状态

思路大概是这样的,接下来我们写一个 demo 来试试如何实现

  1. 创建一个 空的 Android 项目 cn.twle.android.Button

  2. 修改 color.xml 添加几个颜色

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    
        <color name="colorPrimary">#3F51B5</color>
        <color name="colorPrimaryDark">#303f9f</color>
        <color name="colorAccent">#FF4081</color>
    
        <color name="wave_color">#10aa8c</color>
    </resources>
    
  3. 然后在 MainActivity.java 目录下新建一类 WaveButton 继承自 Button

    package cn.twle.android.button;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.drawable.ColorDrawable;
    import android.os.SystemClock;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.ViewConfiguration;
    import android.widget.Button;
    
    public class WaveButton extends Button {
    
        //每次刷新的时间间隔
        private static final int INVALIDATE_DURATION = 15;
    
        //扩散半径增量
        private static int DIFFUSE_GAP = 10;
    
        //判断点击和长按的时间
        private static int TAP_TIMEOUT;
    
        //控件宽高
        private int viewWidth, viewHeight;
    
        //控件原点坐标(左上角)                  
        private int pointX, pointY;
    
        //扩散的最大半径                 
        private int maxRadio;
    
        //扩散的半径                           
        private int shaderRadio;
    
        //画笔:背景和水波纹
        private Paint bottomPaint, colorPaint;
    
        //记录是否按钮被按下       
        private boolean isPushButton;
    
        //触摸位置的X,Y坐标
        private int eventX, eventY;
    
        //按下的时间               
        private long downTime = 0;
    
        public WaveButton(Context context, AttributeSet attrs) {
            super(context, attrs);
            initPaint();
            TAP_TIMEOUT = ViewConfiguration.getLongPressTimeout();
        }
    
        /*
        * 初始化画笔
        */
        private void initPaint() {
            colorPaint = new Paint();
            bottomPaint = new Paint();
    
            int bgcolor = ((ColorDrawable)this.getBackground()).getColor();
    
            colorPaint.setColor(getResources().getColor(R.color.wave_color));
            bottomPaint.setColor(bgcolor);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (downTime == 0) downTime = SystemClock.elapsedRealtime();
                    eventX = (int) event.getX();
                    eventY = (int) event.getY();
    
                    //计算最大半径:
                    countMaxRadio();
                    isPushButton = true;
                    postInvalidateDelayed(INVALIDATE_DURATION);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    if(SystemClock.elapsedRealtime() - downTime < TAP_TIMEOUT){
                        DIFFUSE_GAP = 30;
                        postInvalidate();
                    }else{
                        clearData();
                    }
                    break;
            }
            return super.onTouchEvent(event);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
    
            //如果按钮没有被按下则返回
            if(!isPushButton) {
                // 绘制文本 
                super.onDraw(canvas);
                return;
            }
    
            //绘制按下后的整个背景
            canvas.drawRect(pointX, pointY, pointX + viewWidth, pointY + viewHeight, bottomPaint);
            canvas.save();
    
            //绘制扩散圆形背景
            canvas.clipRect(pointX, pointY, pointX + viewWidth, pointY + viewHeight);
            canvas.drawCircle(eventX, eventY, shaderRadio, colorPaint);
            canvas.restore();
    
            // 很重要,一定要在这里调用绘制文本,不然你会看到 登录两个字消失了
            super.onDraw(canvas);
    
            //直到半径等于最大半径
            if(shaderRadio < maxRadio){
                postInvalidateDelayed(INVALIDATE_DURATION,
                        pointX, pointY, pointX + viewWidth, pointY + viewHeight);
                shaderRadio += DIFFUSE_GAP;
            }else{
                clearData();
            }
        }
    
        /*
         * 计算最大半径的方法
        */
        private void countMaxRadio() {
            if (viewWidth > viewHeight) {
                if (eventX < viewWidth / 2) {
                    maxRadio = viewWidth - eventX;
                } else {
                    maxRadio = viewWidth / 2 + eventX;
                }
            } else {
                if (eventY < viewHeight / 2) {
                    maxRadio = viewHeight - eventY;
                } else {
                    maxRadio = viewHeight / 2 + eventY;
                }
            }
        }
    
        /*
        * 重置数据的方法
        */
        private void clearData(){
            downTime = 0;
            DIFFUSE_GAP = 10;
            isPushButton = false;
            shaderRadio = 0;
            postInvalidate();
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            this.viewWidth = w;
            this.viewHeight = h;
        }
    }
    
  4. 修改 activity_main.xml 添加我们刚刚自定义的 WaveButton

    <?xml version="1.0" encoding="utf-8" ?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <cn.twle.android.button.WaveButton
            android:layout_marginTop="16dp"
            android:id="@+id/myBtn"
            android:text="登 录"
            android:textColor="#ffffff"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#0ac39e" />
    
    </RelativeLayout>
    

参考文档

Android 官方 ImageButton API

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.