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 条评论
登录 后参与评论

相关文章

来自专栏肖蕾的博客

使用这个,自定义AlertDialog在你手里都不是问题

1207
来自专栏飞雪无情的博客

新浪微博布局学习——妙用TabHost

为了更好的开发Android应用程序,除了熟练掌握基本的UI组件和API外,还需要掌握一些技巧,而这些技巧可以通过阅读一些代码来提高,本系列将与大家分享一些新浪...

642
来自专栏向治洪

保存手写签名

Android 提供了很多丰富、实用而且很有特色的功能。比如,语音识别、手写签名等等。本篇就为你介绍如何在android上进行个性化的手写签名。 首先大致说...

2106
来自专栏Android Note

Android-悬浮窗效果FloatingView

1133
来自专栏緣來來來

安卓基础干货(十):安卓多媒体编程的学习

应用程序在启动时系统为它创建一个进程,系统为每个进程创建dalvik虚拟机(模拟器设置的VM Heap),当图片的大小大于虚拟机的堆内存空间时,就内存溢出(内存...

591
来自专栏一“技”之长

Android开发之FrameLayout布局

        在Android开发中,FrameLayout是所有布局容器中最简单的一种,在前边博客中有介绍关于Android开发中线性布局LinearLay...

781
来自专栏Android机动车

轻松实现右滑关闭当前Activity

常常可以看到,很多Android应用都有这么一个功能,就是滑动关闭Activity,比如微信,CSDN移动端,百度贴吧移动端等。我自己也想写个滑动关闭Activ...

571
来自专栏Jack的Android之旅

高仿网易严选底部弹出菜单

在网易严选的看东西的时候在商品详情页里看到他的底部弹出菜单,本能反应是想用DottomSheetDialog或者PopupWindow来实现,可是发现实现不了他...

812
来自专栏增长技术

Android 相机功能模块相关库

Android’s video recording APIs are very difficult to figure out, especially sinc...

971
来自专栏吴小龙同學

Android Design Support Library之BottomNavigation

随着Android 7.1的的发布,相关的开发工具与套件也一起更新了,包括Android Studio 2.2.2与Support Library 25.0.0...

27510

扫码关注云+社区