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