Android - 圆形 Button 与倒计时控件

前言

平时咱们开发 Button 是很常见的控件,它总是以各种形式出现。例如:加边框边框颜色各种圆角。以至于我们不得不写 n 个 shape 文件去维护。这样总是很麻烦,还很容易忘记更改某些文件。所以,我就封装了一个 RoundedButton 来减少一些不必要的操作。

先看图:

public class RoundBtn extends android.support.v7.widget.AppCompatButton {

    private GradientDrawable mShape;

    //不可用颜色
    private int mUnEnableColor;
    //按下颜色
    private int mPressedColor;
    //当前颜色
    private int mNormalColor;
    //当前圆角
    private float mBorderCorner;
    //四边边框宽度
    private float mStrokeWidth;
    //四边边框颜色
    private int mBorderColor;
    /**
     *  倒计时时间,如果要从初始值开始倒计时,需要多加 1(要从 5 秒开始,得写 6)
     */
    protected int mCountDownTime;

    private boolean mIsTouchPass = true;

    private boolean mIsEnable;

    private Context mContext;

    public RoundBtn(Context context) {
        this(context,null);
    }

    public RoundBtn(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public RoundBtn(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext=context;
        initView(context,attrs);
    }

    private void initView(Context context, AttributeSet attrs){
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RoundBtn);
        mUnEnableColor = ta.getColor(R.styleable.RoundBtn_bgUnAbleColor, ContextCompat.getColor(context,R.color.light_blue_color));
        mNormalColor = ta.getColor(R.styleable.RoundBtn_bgAbleColor, ContextCompat.getColor(context,R.color.blue_color));
        mPressedColor = ta.getColor(R.styleable.RoundBtn_bgPressColor, ContextCompat.getColor(context,R.color.more_blue_color));
        mBorderColor = ta.getColor(R.styleable.RoundBtn_edgeColor, ContextCompat.getColor(context,R.color.blue_color));
        mStrokeWidth = ta.getInt(R.styleable.RoundBtn_edgeWidth, dp2px(context, 0));
        mBorderCorner =ta.getFloat(R.styleable.RoundBtn_roundRadius, dp2px(context, 0));
        mIsEnable = ta.getBoolean(R.styleable.RoundBtn_isEnable, true);
        mCountDownTime = ta.getInteger(R.styleable.RoundBtn_countTime, 1);

        mShape = new GradientDrawable();
        mShape.setShape(GradientDrawable.RECTANGLE);
        mShape.setCornerRadius(dp2px(context,mBorderCorner));

        setBtnStyles();
        setGravity(Gravity.CENTER);
        ta.recycle();
    }

    private void setBtnStyles() {
        setEnabled(mIsEnable);

        if(mIsEnable) {
            mShape.setColor(mNormalColor);
        }else{
            mShape.setColor(mUnEnableColor);
        }

        if (mBorderColor != 0) {
            mShape.setStroke((int) dp2px(mContext,mStrokeWidth), mBorderColor);
        }

        setBackgroundDrawable(mShape);

        if(mIsEnable) {
            //设置点击按钮之后的颜色更换
            setOnTouchListener((arg0, event) -> {
                setBackgroundDrawable(mShape);
                return setColor(event.getAction());
            });
        }

    }

    //处理按钮点击事件无效
    @Override
    public void setOnClickListener(OnClickListener l) {
        super.setOnClickListener(l);
        mIsTouchPass = false;
    }

    //处理按下去的颜色
    public boolean setColor(int action) {
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mShape.setColor(mPressedColor);
                break;
            case MotionEvent.ACTION_UP:
                mShape.setColor(mNormalColor);
                break;
            case MotionEvent.ACTION_CANCEL:
                mShape.setColor(mNormalColor);
                break;
        }

        return mIsTouchPass;
    }
    /**
     * 设置是否可点击
     */
    public RoundBtn setEnable(boolean isEnable){
        mIsEnable=isEnable;
        setBtnStyles();
        return this;
    }
}

代码很简单,下面我们来看看自定义属性设置

    <!-- 圆角 btn -->
    <declare-styleable name="RoundBtn">
        <attr name="bgUnAbleColor" format="color"/>
        <attr name="bgAbleColor" format="color"/>
        <attr name="bgPressColor" format="color"/>
        <attr name="edgeColor" format="color"/>
        <attr name="edgeWidth" format="integer"/>
        <attr name="roundRadius" format="float"/>
        <attr name="isEnable" format="boolean"/>
        <attr name="countTime" format="integer"/>
    </declare-styleable>

好了,代码就这么多了。

这里,我又顺便封装了一个,倒计时控件。

public class CountDownBtn extends RoundBtn {

    private Disposable mDisposable;

    public CountDownBtn(Context context) {
        this(context, null);
    }

    public CountDownBtn(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CountDownBtn(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    private void initView(Context context) {
        //explain start:起始数值 count:发射数量  initialDelay:延迟执行时间 period:发射周期时间  unit:时间颗粒度
        setText(context.getString(R.string.send_code_msg));
        setOnClickListener(view -> {

            if (mListener != null) {
                mListener.start();
            }

            mDisposable = Flowable.intervalRange(1, mCountDownTime, 0, 1, TimeUnit.SECONDS)
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnNext(aLong -> {
                        setEnable(false);
                        setText(context.getString(R.string.get_code_msg_again) + " " + ((mCountDownTime) - aLong) + " 秒");
                    })
                    .doOnComplete(() -> {
                        setEnable(true);
                        setText(context.getString(R.string.send_code_msg));
                    })
                    .subscribe();
        });
    }



    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        if (mDisposable != null && !mDisposable.isDisposed()) {
            mDisposable.dispose();
            mDisposable = null;
        }

        if (mListener != null) {
            mListener=null;
        }
    }

    private ISendCodeListener mListener;

    public void setISendCodeListener(ISendCodeListener listener) {
        mListener=listener;
    }

    public interface ISendCodeListener{
        void start();
    }
}

使用方法:

CountDownBtn countDownBtn = findViewById(R.id.id_count_down_btn);
countDownBtn.setISendCodeListener(() -> Toast.makeText(CustomBtnActivity.this, "验证码已发送", Toast.LENGTH_SHORT).show());

到这里内容就结束啦。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏闻道于事

js登录滑动验证,不滑动无法登陆

js的判断这里是根据滑块的位置进行判断,应该是用一个flag判断 <%@ page language="java" contentType="text/html...

6948
来自专栏陈仁松博客

ASP.NET Core 'Microsoft.Win32.Registry' 错误修复

今天在发布Asp.net Core应用到Azure的时候出现错误InvalidOperationException: Cannot find compilati...

4868
来自专栏大内老A

The .NET of Tomorrow

Ed Charbeneau(http://developer.telerik.com/featured/the-net-of-tomorrow/) Exciti...

31810
来自专栏ASP.NETCore

ASP.NET Core 整合Autofac和Castle实现自动AOP拦截

除了ASP.NETCore自带的IOC容器外,我们还可以使用其他成熟的DI框架,如Autofac,StructureMap等(笔者只用过Unity,Ninjec...

674
来自专栏码匠的流水账

聊聊NettyConnector的start及shutdown

reactor-netty-0.7.6.RELEASE-sources.jar!/reactor/ipc/netty/NettyConnector.java

881
来自专栏跟着阿笨一起玩NET

c#实现打印功能

2802
来自专栏魂祭心

原 canvas绘制clock

4164
来自专栏pangguoming

Spring Boot集成JasperReports生成PDF文档

由于工作需要,要实现后端根据模板动态填充数据生成PDF文档,通过技术选型,使用Ireport5.6来设计模板,结合JasperReports5.6工具库来调用渲...

1.2K7
来自专栏hbbliyong

WPF Trigger for IsSelected in a DataTemplate for ListBox items

<DataTemplate DataType="{x:Type vm:HeaderSlugViewModel}"> <vw:HeaderSlug...

4064
来自专栏转载gongluck的CSDN博客

cocos2dx 打灰机

#include "GamePlane.h" #include "PlaneSprite.h" #include "BulletNode.h" #include...

5556

扫码关注云+社区