Android EditText限制输入的最大字符数

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

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值