EditText根据字节长度拦截输入内容


前言

本次记录的是一个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;
    }
}

总结

古惑仔不用脑,一世都是飞机。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值