一、简述
监听EditText的输入是一个十分常见的需求,但是使用setOnEditorActionListener、addTextChangedListener等接口来监听输入不够灵活,而且如果有多种过滤条件,则方法里的逻辑会非常复杂。
推荐使用实现自己输入过滤器来过滤输入内容,使用方便、灵活,而且官方已经实现了许多常用的过滤器。
InputFilter
public interface InputFilter
android.text.InputFilter
Known indirect subclasses
DateKeyListener, DateTimeKeyListener, DialerKeyListener, DigitsKeyListener, InputFilter.AllCaps, InputFilter.LengthFilter, LoginFilter, LoginFilter.PasswordFilterGMail, LoginFilter.UsernameFilterGMail, LoginFilter.UsernameFilterGeneric, NumberKeyListener, TimeKeyListener
使用方法
//通过EditText 的setFilters方法设置,可以传入多个Filter
setFilters(new InputFilter[]{new LengthFilter(maxLength),new CustomFilter()});
二、详细讲解InputFilter API,和如何自定义一个InputFilter
首先这是API的链接(需要翻墙 如果看不到也没关系,下面有详细内容)
https://developer.android.com/reference/android/text/InputFilter
API中的定义
/**
* 当缓冲区要使用source的[start - end)范围内的内容替换dest的[dstart - dend)范围内的内容时调用该方法。
* 返回值是你最终想要添加的文本。如果返回空字符"",则不添加新内容。如果返回空(null),则添加本次输入的全部内容(即source)
* 当你在删除已有文本时,source的长度为0。不要以为是错误而过滤这种清空。
* 不要直接修改dest的内容,它的内容只是用来查看的。
*/
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend);
方法描述:
使用source的下标范围[start--end)的内容,替换dest的下标范围是[dstart-dend)的内容。两个区间都是左闭右开 .end-start是本次输入的字数,dend-dstart是本次被替换的字数。
参数说明:
CharSequence source :本次输入内容
int start :本次输入被选择的起始位置
int end:本次输入被选择的结束位置(不包含)
Spanned dest : 当前输入框中的内容
int dstart :被替换内容在输入框中的起始位置
int dend :被替换内容在输入框中的结束位置(不包含)
返回值说明:
返回值是本次输入最终被输入的内容。有以下三种情况
- 返回空字符串:""。 放弃本次输入,即本次输入不会添加到输入框中
- **返回空值:null。 **将本次输入完全完全添加到输入框中,相当于return source(不建议使用return source)
- **返回指定有内容的字符串:你希望的输入(如"12345")。 **次将指定的字符串添加到输入框中(如"12345")
声明:
被替换内容是指:当选择输入框里的内容,然后输入新的字符,选择的内容将会被新输入的字符替换。这些选择的内容就是被替换的内容。
如果觉得参数不好理解,参考下面的输入实例。
本次输入 b
source = b
start = 0, end =1
dest =
dstart = 0, dend =0
本次输入n
source = n
start = 0, end =1
dest = b
dstart = 1, dend =1
本次输入 m
source = m
start = 0, end =1
dest = bn
dstart = 2, dend =2
本次输入 s
source = s
start = 0, end =1
dest = bnm
dstart = 3, dend =3
本次输入 s
source = s
start = 0, end =1
dest = bnms
dstart = 4, dend =4
本次输入 s
source = s
start = 0, end =1
dest = bnmss
dstart = 5, dend =5
本次输入 孙健
source = 孙健
start = 0, end =2
dest = bnmsss
dstart = 6, dend =6
本次输入 刘德华
source = 刘德华
start = 0, end =3
dest = bnmsss孙健
dstart = 8, dend =8
输入前选中 【刘德华】 然后输入 【张学友****】替换【刘德华】
source = 张学友
start = 0, end =3
dest = bnmsss孙健刘德华
dstart = 8, dend =11
输入前选中 【张学友】**** 然后输入 【黎明****】替换【张学友】
source = 黎明
start = 0, end =2
dest = bnmsss孙健张学友
dstart = 8, dend =11
参数看懂了,我们就来了解一下如何来自定义我们需要的过滤器。
以SDK中已经提供的输入长度过滤器LengthFilter来作为例子,看一下是如何实现限制输入字数的。
/**
* This filter will constrain edits not to make the length of the text
* greater than the specified length.
*/
public static class LengthFilter implements InputFilter {
private final int mMax;
public LengthFilter(int max) {
mMax = max;
}
public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
int dstart, int dend) {
int keep = mMax - (dest.length() - (dend - dstart)); //剩余可以输入的字数
if (keep <= 0) {
return ""; //如果没有剩余可输入字数 则保持原有文本不变
} else if (keep >= end - start) {
// keep original 如果剩余可输入字数大于当前正在输入的字数 则返回当前输入
//(相当于 return source,不过不建议这么写)
return null;
} else {//如果当前输入大于剩余可输入字数,则截取当前输入的剩余可输入字数的字符作为返回值
keep += start;
if (Character.isHighSurrogate(source.charAt(keep - 1))) {
--keep;
if (keep == start) {
return "";
}
}
return source.subSequence(start, keep);
}
}
/**
* @return the maximum length enforced by this input filter
*/
public int getMax() {
return mMax;
}
}
上面的注释代码已经详细说明了如何实现filter()方法。
三、定义一个只能输入数字的过滤器
思路:
数字在ASCII中的分为是[48,57],只要在该范围内都是数字。
代码实现:
//通过匿名内部类的方法来实现。如果考虑复用,可以单独声明一个类
InputFilter DigitalFilter = new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if(source.length() <= 0){return "";}
char [] newChar = new char[source.length()];
//去掉source中不是数字的字符
for(int i=source.length();--i>=0;){
int chr=source.charAt(i);
if(chr > 47 && chr < 58){
newChar[i] = (char) chr;
}
}
//newChar数组中没有赋值的项,在转换为String会被丢弃
return new String(newChar);
}
};
总结:
其实自定义过滤器的难点是理解filter接口的各个参数的意义和返回值表达的含义(api定义注释里的三种情况:""空字符串、null空值、有内容字符串)。我翻译的注释里其实已经解释的很清楚了,如果不要理解看了下面的实际输入的例子应该也能理解了。
只要理解上述内容,根据自己的实际需求返回合适的值即可。
网友评论