需求:EditTtext需要限定输入的字符数量,一个汉字字符占据的是2个字符,一个英文字符占据1个字符。实时监听输入的字符数量,超过字符提示内容长度超限
实现思路:通过EditText的InputFilter过滤器实现。
1、查看InputFilter这个类,里面有个实现好的限制输入文本长度的静态类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) {
return null; // keep original
} 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;
}
}
核心代码就在
public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
int dstart, int dend)
上面的方法中source表示将要写入的字符,start表示输入字符的首尾下标,end表示输入字符的末尾下标,dest表示文本框中已经存在的字符,dstart表示输入字符将要插入的开始位置,dend表示输入字符将要插入的结束位置。(因为可能你在文本框中已经存在的字符中插入,或者你选中几个字符进行粘贴,所以开始位置和结束位置可能不一样)
//这一行计算出你还能够输入的字符长度
int keep = mMax - (dest.length() - (dend - dstart));
//如果能够输入的字符小于等于0,将不能输入字符
if (keep <= 0) {
return "";
//如果可输入的长度大于等于即将输入的字符长度,就不用管
} else if (keep >= end - start) {
return null; // keep original
} else {
//如果可输入的字符在输入字符长度的中间
//先设置输入字符最后字符的下标
keep += start;
//如果最后一个字符在(\uD800-\uDBFF)之间
if (Character.isHighSurrogate(source.charAt(keep - 1))) {
--keep;
//下标减1如果等于开始位置就不让输入
if (keep == start) {
return "";
}
}
return source.subSequence(start, keep);
}
上面的这个能够设置输入的最大字符数,但是他对所有的字符都是一个字符占一个长度来计算了。所以要实现1个汉字占2个字符,1个字符占一个字符就要判断字符是什么类型
2、实现需求效果,具体逻辑如下
override fun filter(source: CharSequence?, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence? {
//限定字符数量
var dindex = 0
var count = 0
var currentLength = 0.0
//计算文本框中已经存在的字符长度
while (count <= maxLength && dindex < dest?.length!!) {
val c = dest[dindex++]
//这里是根据ACSII值进行判定的中英文,其中中文及中文符号的ACSII值都是大于128的
if (c.toInt() <= 128) {
count += 1
if(count<=maxLength) {
currentLength += 0.5
}
} else {
count += 2
if(count<=maxLength) {
currentLength++
}
}
}
if (count > maxLength) {
UtilDialog.showToast(context.getString(R.string.core_content_byound_max), Gravity.CENTER)
callback?.invoke(Math.ceil(currentLength).toInt())
return dest?.subSequence(0, dindex - 1)
}
//计算输入的字符长度
var sindex = 0
while (count <= maxLength && sindex < source?.length!!) {
val c = source[sindex++]
if(c.toInt() <= 128){
count+=1
if(count<=maxLength) {
currentLength += 0.5
}
}else{
count+=2
if(count<=maxLength) {
currentLength++
}
}
}
if (count > maxLength) {
UtilDialog.showToast(context.getString(R.string.core_content_byound_max), Gravity.CENTER)
sindex--
}
//计算删除的字符的长度
if (start == 0 && end == 0) {
val delete = dest?.subSequence(dstart, dend) ?: ""
for (deleteIndext in 0 until delete.length) {
val c = delete[deleteIndext]
if (c.toInt() <= 128) {
currentLength -= 0.5
} else {
currentLength--
}
}
}
callback?.invoke(Math.ceil(currentLength).toInt())
return source?.subSequence(0, sindex)
}