前言
本次记录的是一个EditText输入,需要根据输入内容的字节大小来拦截输入内容的小功能。
如果你急需一个这样的功能类,直接翻到末尾复制
一、我的思路
首先我想到的使用EditText的内容监听去做这件事情,将监听回来的内容经过处理判断后再将内容再次写入到EditText中,但是这种做法在使用中会有诸多的问题.比如:
1.你只能将输入的内容从开始到末尾进行处理,无法从输入内容的光标位置处理数据,简而言之就是只知道输入的内容而不知道输入内容的方式.
2.这种方式需要二次对EditText进行内容注入,所以需要在对内容的监听处理上做一次拦截处理,不然会死循环,所以这里在代码的处理上是很不优雅的
所以不优先考虑这种方式
后来想起EditText本身就有InputFilter过滤器这种工具,何乐不为呢?
EditText.setFilters(new InputFilter[]{filter});
二、简介属性
要实现过过滤器功能,首先要实现InputFilter接口,重写他的filter方法
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
//source 输入的内容
//start 输入内容的开始位置
//end 输入内容的结束位置
//dest 输入之前显示内容
//dstart 显示内容的初始位置
//dend 显示内容的结束位置
return null;
}
根据这里内容的解释大致能了解到过滤器的参数作用,前面三个是处理输入内容的参数,后面三个是处理原有显示数据的参数.那么到这里之后我本着敲代码应该严谨态度,在代码中打印一下log,看看那运行结果到底是否如所想的一样。先写一个TestInputFilter重新写filter方法打印log
public class TestInputFilter implements InputFilter {
@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
Log.e("PWDebug", "source = " + source + " start = " + start + "" + " end = "
+ end + " dest = " + dest + " dstart = " + dstart + " dend = " + dend);
return null;
}
}
在MainActivity的onCreate中写出实现代码,现在就可以在界面中输入内容查看log了
TestInputFilter filter = new TestInputFilter();
EditText etInput = findViewById(R.id.et_input_view);
etInput.setFilters(new InputFilter[]{filter});
首先我在输入框中输入一个文字“我”字
E/PWDebug: source = 我 start = 0 end = 1 dest = dstart = 0 dend = 0
一次输入多个字符
E/PWDebug: source = 要像风一样自由 start = 0 end = 7 dest = 我 dstart = 1 dend = 1
在文字中间输入
E/PWDebug: source = 子 start = 0 end = 1 dest = 我要像风一样自由 dstart = 4 dend = 4
从末尾删除
E/PWDebug: source = start = 0 end = 0 dest = 我要像风子一样自由 dstart = 8 dend = 9
从中间删除
E/PWDebug: source = start = 0 end = 0 dest = 我要像风子一样自 dstart = 4 dend = 5
删除第一个
E/PWDebug: source = start = 0 end = 0 dest = 我要像风一样自 dstart = 0 dend = 1
根据上述log可以发现输入和删除中参数变化的一些规律。
1.输入内容时后两位的参数是相等的,前两位参数的差值表示了输入内容的长度。
2.删除内容时前两位参数是相等的,后两位参数出现了差值,并表现出了长度和位置。
到这里似乎可以进行对InputFilter 的重写了,返回值如何处理具体可以参考改方法下的注释,或在使用这个方法的源码下追溯结果,通过源码追溯
SpannableStringBuilder类是使用EditText 设置的InputFilter数组的地方,在他的
replace(final int start, final int end,CharSequence tb, int tbstart, int tbend)方法下做具体使用
// Documentation from interface
public SpannableStringBuilder replace(final int start, final int end,
CharSequence tb, int tbstart, int tbend) {
checkRange("replace", start, end);
int filtercount = mFilters.length;
for (int i = 0; i < filtercount; i++) {
CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
if (repl != null) {
tb = repl;
tbstart = 0;
tbend = repl.length();
}
}
..........
这里代码逻辑太长,不做详细解释
三、功能实现
根据二中的属性介绍以及log结果,我们可以开始进行功能的实现
1.既然是根据字节限制长度,我们首先声明相关属性,最大值和当前值
/**
* 最大字节长度
*/
private int maxByteLength = 0;
/**
* 字节长度
*/
private int byteCount;
2.过滤器拦截重写
因为是长度限制的缘故首先我们根据2.3位参数和后两位参数来判断是输入或者删除
可以通过
if (start == end && dstart != dend)
//输入数据不变,原有数据变化--表示在删除文字
和
if (start != end && dstart == dend)
//输入数据变化,原有数据不变--表示在输入文字
来做出判断,进而对逻辑处理
四、完整功能代码复制粘贴即可使用,岂不美滋滋
/**
* 输入框字节长度拦截过滤器
*/
public class ByteSizeLimitInputFilter implements InputFilter {
public static final int THRESHOLD = 128;//临界点
/**
* 最大字节长度
*/
private int maxByteLength = 0;
/**
* 字节长度
*/
private int byteCount;
public ByteSizeLimitInputFilter(int maxByteLength) {
this.maxByteLength = maxByteLength;
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
byteCount = 0;
if (start == end && dstart != dend) {
//输入数据不变,原有数据变化--表示在删除文字
//由于是限制最大长度的,所以这里只需要计算有效字节
int destIndex = 0;
int lastCharSize = 0;
while (byteCount < maxByteLength && destIndex < dest.length()) {
char indexChar = dest.charAt(destIndex++);
if (destIndex <= dstart || destIndex > dend) {
//再变动字符之前和之后的字符属于未删除的字符
lastCharSize = (indexChar < THRESHOLD ? 1 : 2);
byteCount = byteCount + lastCharSize;
}
}
return source.subSequence(0, 0);
} else if (start != end && dstart == dend) {
//输入数据变化,原有数据不变--表示在输入文字
//先计算原有数据长度
int destIndex = 0;
int lastCharSize = 0;
while (byteCount < maxByteLength && destIndex < dest.length()) {
char indexChar = dest.charAt(destIndex++);
//在变动字符之前和之后的字符属于未删除的有效字符
lastCharSize = (indexChar < THRESHOLD ? 1 : 2);
byteCount = byteCount + lastCharSize;
}
if (byteCount > maxByteLength) {
//如果原有数据已经超长,拦截回去
byteCount = byteCount - lastCharSize;
return dest.subSequence(0, destIndex - 1);
} else {
//如果原有数据长度不够,继续计算输入数据
int sourceIndex = 0;
while (byteCount < maxByteLength && sourceIndex < source.length()) {
char indexChar = source.charAt(sourceIndex++);
lastCharSize = (indexChar < THRESHOLD ? 1 : 2);
byteCount = byteCount + lastCharSize;
}
if (sourceIndex > 0 && byteCount > maxByteLength) {
byteCount = byteCount - lastCharSize;
sourceIndex--;
}
return source.subSequence(0, sourceIndex);
}
}
return source;
}
/**
* 获取字节长度
*/
public int getByteCount() {
return byteCount;
}
}
总结
古惑仔不用脑,一世都是飞机。