1.介绍
如果要实时监控EditText的输入情况。根据输入的情况进行其他事务的响应。
那么我们只需要在EditText控件上添加TextWatcher的监听。就可以把握整个EditText 的输入前,输入中,以及输入后的状态。
其他的EditText的扩展的例如:TextInputEditText也是支持TestWatcher的监控的。
2. TextWatcher详解
在使用前,我们先了解TextWatcher这个对象。
TextWatcher 是一个接口类。主要有以下三个方法:
void beforeTextChanged(CharSequence var1, int var2, int var3, int var4);
//文本内容改变前
void onTextChanged(CharSequence var1, int var2, int var3, int var4);
//文本内容改变中
void afterTextChanged(Editable var1);
//文本内容改变后
从方法名上,我们就可以很简单的区分三个接口到底是干嘛了。
关键是它的几个接口传参到底是怎么使用的。
2.1 接口的调动顺序
我们先了解这三个接口是怎么调用的:
zinyenEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
Log.e("TextInputEditText", "beforeTextChanged 修改前:" + charSequence);
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
Log.e("TextInputEditText", "onTextChanged 修改中:" + charSequence);
}
@Override
public void afterTextChanged(Editable editable) {
Log.e("TextInputEditText", "afterTextChanged 修改后:" + editable.toString());
}
});
然后我们输入不同的情况下。看看它的日志输出结果是如何的。
- 光标点击时:TextWatcher事件不会被触发
- EditText.setText():TextWatcher事件会被触发。分别从上到下执行,
beforeTextChanged
,onTextChanged
,afterTextChanged
。不管setText()
里面是否有传值,都会触发TextWatcher事件。
下面看看在输入的情况下,会有什么结果:
2.1.1 添加字符
EditText 输入z
E/TextInputEditText: beforeTextChanged 修改前:
E/TextInputEditText: onTextChanged 修改中:z
E/TextInputEditText: afterTextChanged 修改后:z
效果图如下:
我们如果继续输入,可以看到我们一直往后输入,那么修改中和修改后的结果是一样的。
那么我们如果光标移动到中间会是什么效果呢?我们将光标移动到开头,进行输入得到的效果如下。
2.1.2 删除字符
我们如果删除前面的Yan 会是什么效果呢?
2.1.3 修改字符
例如剪切和粘贴。整个修改添加状态是一样的。只是不会在一个一个字符进行监控而已。
例如剪切
粘贴:
通过上面的例子我们可以看到。EditText输入框中的所有字符的变动情况,我们如果要匹配用户输入的长度,用户当前输入的结果等等,都可以通过这个进行监听获取结果了。
上面的三个接口变动顺序很快,而且永远都是beforeTextChanged
->onTextChanged
->afterTextChanged
这个顺序进行执行的。
2.2 接口各参数介绍
上面的例子介绍了CharSequence 的变动,后面的几个参数的变动我直接写了。就不进行示例打印了。因为大部分情况下,我们也用不上。
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
- CharSequence charSequence: editText 修改前的字符串
- int var2: 字符串中要开始发生修改的位置(也就是我们光标的位置)
- int var3: 字符串中即将被修改的文字的长度(如果光标在最后,那么就是0)
- int var4: 字符串中被修改的文字长度。如果是删除的话就是0
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
- CharSequence charSequence: 当前修改后的字符串
- int i: 有变动的字符串的下标值
- int i1: 被改变的字符串长度,如果是新增长度为0
- int i2: 添加的字符串长度,如果是删除值为0
public void afterTextChanged(Editable editable)
- Editable editable: 修改后的字符串。
其实不建议在TextWatcher的函数中,执行EditText字符串的修改。我们只是用它来监听输入指定长度,或者输入匹配正则的结果时,我们执行其他的动作而已。
3.避免死循环
1.我们开头就说了。如果调用setText 方法,就会触发TextWatcher事件。我们如果在beforeTextChanged,onTextChanged,afterTextChanged 这三个方法中,任意地方进行setText修改都会造成死循环一直重复触发TextWatcher
2.我们如果在afterTextChanged 方法中,修改Editable对象,也会进行死循环。
解决方法:
zinyanEdit.removeTextChangedListener(TextWatcher);
zinyanEdit.setText("修改结果");
zinyanEdit.addTextChangedListener(TextWatcher);
我们在必须修改的地方,先执行remove移除TextWatcher监听。然后修改完毕后,再add加入TextWatcher监听。也能规避。
但是这种就不够优雅了。
本质上来说,这个接口只是用来监听输入的内容和长度的,并不太建议在这个方法中进行字符串的替换。
如果要在输入过程中进行字符替换修改。建议使用InputFilter
进行监听。
评论区