让“提交”按钮状态跟随edittext以及checkbox等的状态实时变化

现在很多应用在对于提交按钮是否可以点击的判断都是随着用户输入的内容或者勾选的状态而变化的,应该很少有人会如果用户在界面上没有任何输入的时候就让其开始点击按钮吧。这样做首先是增加了用户无谓的操作。另外也是会增加很多的非空判断,实在是不划算。所以才会有这种 如果该输入的还没有输入,该选择的没有任何勾选,那么提交按钮就不点亮还处于不可点击状态这样的设计了。
  好,其实今天跟大家说的就是自己现在在用的一个对于这种状态判断与控制的工具类了。下面直接看代码。

/**
 * Created by hexiaopang on 2016/11/4.
 * 一个监听 edittext,checkbox是否有输入和选中,然后改变“提交”按钮的可提交状态
 * 只需要将需要监控的控件例如EditText,CheckBox添加进来,再设置“提交”按钮即可
 */
public class SubmitControl {
    private List<View> listViews = null;//用于存储 组件的list集合
    private MyTextWatcher myWatcher = null;//edittext以及textview是否有输入的监听
    private MyOnCheckedChangedListener myCheckedListener;//checkbox的选中状态监听
    private TextView submitButton;//提交“按钮”
    private static SubmitControl myControl;

    /**
     * 获取 单例实例(懒汉式)
     */
    public static SubmitControl getInstance() {
        if(myControl == null){
            myControl = new SubmitControl();
        }
        return myControl;
    }

    /**
     * 初始化数据 这个是必须得首先调用的,否则会出现混乱错误
     */
    public void initConroller() {
        if (listViews == null) {
            listViews = new ArrayList<View>();
        } else {
            listViews.clear();
        }
        myWatcher = new MyTextWatcher();
        myCheckedListener = new MyOnCheckedChangedListener();
    }

    /**
     * 添加view组件(这个view可以是textview或者是edittext或者是checkbox了)
     */
    public void addView(View... views) {
        for (View viewTemp : views) {
            if (!listViews.contains(viewTemp)) {
                if(viewTemp instanceof CheckBox){
                    ((CheckBox)viewTemp).setOnCheckedChangeListener(myCheckedListener);
                }else if(viewTemp instanceof TextView){
                    ((TextView)viewTemp).addTextChangedListener(myWatcher);
                }
                listViews.add(viewTemp);
            }
        }
    }

    //将某个组件从监控状态中移除
    public void remove(View... views) {
        for (View view : views) {
            //如果list中有 要移除的元素的话
            if(listViews.contains(view)){
                if (view instanceof CheckBox) {
                    ((CheckBox) view).setOnCheckedChangeListener(null);
                }else if (view instanceof TextView) {
                    ((EditText) view).removeTextChangedListener(myWatcher);
                }
                listViews.remove(view);
            }
        }
    }

    /**
     * checkbox的监听
     */
    private class MyOnCheckedChangedListener implements OnCheckedChangeListener {

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            changeSubmitStatus();
        }
    }

    /**
     * edittext的监听
     */
    private class MyTextWatcher implements TextWatcher {

        @Override
        public void afterTextChanged(Editable s) {
            changeSubmitStatus();
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

    }

    /**
     * 根据 各种组件状态的改变,来设置提交按钮是否可点击
     * 貌似避免不了遍历
     */
    private void changeSubmitStatus() {
        int count = 0;
        for (int i = 0; i < listViews.size(); i++) {
            if (listViews.get(i) instanceof CheckBox) {
                if (((CheckBox) listViews.get(i)).isChecked()) {
                    count++;
                } else {
                    break;
                }
            }else if (listViews.get(i) instanceof TextView) {
                if (!TextUtils.isEmpty(((TextView) listViews.get(i)).getText().toString())) {
                    count++;
                } else {
                    break;
                }
            }
        }
        if (submitButton == null) {
            throw new NullPointerException("你至少得调用setSubmitButton()方法设置一个提交按钮吧");
        }
        submitButton.setEnabled((count == listViews.size()));
    }

    /**
     * 设置提交按钮
     * 并且提交按钮的状态改变是通过 textview或者edittext或者checkbox的对应赋值方法调用时候才会改变
     */
    public void setSubmitButton(TextView button) {
        this.submitButton = button;
    }
}```
  我们来看下这个类,上面声明的变量就不说了。注释写的很清楚了,哈哈哈。首先是initConroller了。这个方法就是初始化存放view的list集合,如果不为空我们进行清空,因为我们类是单例的,所以如果list不为null,那么一定是存放着上个页面的view,所以用的时候必须要进行清空了。同样监听也必须new出来。其次是addview方法了,其实是可以一次添加多个的,我们转化出来就是一个数组了。同样我们参数类型是view,因为我们对于要监听的任何控件基本都是继承自view了。而方法内部则是对于view进行了区分,我们这里就是对于textview(edittext也是继承自textview嘛)和checkbox加上监听了,然后添加入我们的view的集合。我们同时也提供了将view移除监听的方法就是remove方法了,这个或许会很少用到。但是万一有这样的业务需求呢。下面的两个内部类就是对于textview以及checkbox的监听的具体实现。我们可以看到在textview(当然更多的是Edittext)的监听的afterTextChanged方法以及checkbox的监听的onCheckedChanged方法中都调用了changeSubmitStatus方法了。这个方法大家也可以看到是在我们需要监控的控件的状态改变的时候会被调用的了。首先是一个变量count,然后是进行一次遍历, 如果遍历到的当前view是checkbox就看其是否是checked状态,是的话count+1,否的话直接break,没有必要继续循环下去,因为这就一定代表组件没有输入或者没有勾选嘛,我们的“提交按钮”是不可以点击的了。同样如果遍历到的是textview就看其是否为非空,是的话count+1,否的话也是直接break了,原因同上。在循环的最后我们拿这个count和存放view的list集合的元素个数进行比较,如果相等则是代表所有需要输入的或者勾选的都已经勾选和非空了。按钮便就enable可以点击了。当然如果“提交按钮”都没有设置,那就没法玩耍了。就直接给调用方抛出一个异常吧。哈哈,所以最后一个方法就是设置“提交按钮的了”。 
  代码就是这样子的。再说下调用了。例如下面这样子:

@Override
public void setController() {
super.setController();
SubmitControl.getInstance().initConroller();
SubmitControl.getInstance().addView(verifyEt);
SubmitControl.getInstance().setSubmitButton(submitBtn);
}```
  其实有一点特别重要的是我们的这个setController方法一定要放在Activity的onResume方法里面。因为我们的类是单例的。好比在界面A有有一些设置,然后跳转到页面B,但是A未销毁,然后又返回了A,若此时不调用setController其实还是在监听B页面的按钮以及输入框等的状态了。当然了,我们一般都会有个BaseActivity就是基类,其实在基类里面写个方法setController,然后在基类的onResume里面调用就好了。
  以上如有问题,欢迎批评指正。有问题,也欢迎一起讨论。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容