需求: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) }