【bug杂记1】限制EditText文本长度

我到底想要干啥?

需求的本意是EditText只能输入不超过一行的文字并且不会出现"…",所以简单使用singleLine来实现这个效果肯定不行,那么下一个思路就是通过添加TextWatcher对文本变化进行监听,并且通过不断measure文字的宽度并且不断截取文字来使文字短到可以被控件显示下,所以使用substring来实现这个需求,重点就在截取文字的代码,所以我的第一版本是酱紫的

简单实现V0.9

public String adjustText(TextView textView, String text) {
    String tmpTxt = null;
    // 要求只能显示一行的文字宽度不能换行
    if (textView != null && text != null) {
        // 为了避免substring删除emoji等多个char的元素导致的错误截取
        int codePointCount = text.codePointCount(0, text.length());
        for (int i = codePointCount; i >= 0; i--) {
            int offset = text.offsetByCodePoints(0, i);
            if (StringUtil.isEmpty((tmpTxt = text.substring(0, offset)))
                    || (textView.getPaint().measureText(tmpTxt) + textView.getPaddingLeft()
                    + textView.getPaddingRight()) < textView.getWidth()) {
                break;
            }
        }
    }
    return tmpTxt == null ? "" : tmpTxt;
}

简单测试了试了几次,输入中文或者英文字符乍一看是没有问题的,结果为了卖萌输入了这个emoji表情,就出现了乱码,纳尼?什么鬼。可是到底是歪?

为啥用substring之后就乱码了呢?

原来Java对于普通的字符char使用2个字节存储,而中文和emoji等使用2个char(4字节)存储,但是substring是直接截取是针对单个char的,直接把emoji的char给人家截断了,当然就显示乱码喽~

怎么解决乱码问题呢?

原因知道了,可是怎么解决呢。原来Java早就考虑到这种问题啦,通过codePointCount可以获取有效的代码点。啥是代码点,理解为一个完整的字符(可能1个char,也可能2个char),比如一个emoji表情就认为是一个代码点,通过offsetByCodePoints可以获取第i个代码点距离其实下标的距离,通过substring就可以获取正确的字符串啦,就不存在截取一半emoji的尴尬情况啦,整理下,代码如下~

简单实现V1.0

public String adjustText(TextView textView, String text) {
    String tmpTxt = null;
    // 要求只能显示一行的文字宽度不能换行
    if (textView != null && text != null) {
        // 为了避免substring删除emoji等多个char的元素导致的错误截取
        int codePointCount = text.codePointCount(0, text.length());
        for (int i = codePointCount; i >= 0; i--) {
            int offset = text.offsetByCodePoints(0, i);
            if (StringUtil.isEmpty((tmpTxt = text.substring(0, offset)))
                    || (textView.getPaint().measureText(tmpTxt) + textView.getPaddingLeft()
                    + textView.getPaddingRight()) < textView.getWidth()) {
                break;
            }
        }
    }
    return tmpTxt == null ? "" : tmpTxt;
}

这个情况处理完毕,处理完字符串的截取在onTextChanged方法中调用EditText的setText来实现截取(注意设置前一定要比较当前的文本和设置的文本哦,不然就要StackOverFlow啦),尴尬的是又存在了另一个问题,就是光标问题呀,不能每次截取都要把光标移到最后面吧。所以通过设置前备份下光标位置即可,代码如下

int selectionStart = mEditText.getSelectionStart();
mEditText.setText(handledText);
mEditText
    .setSelection(selectionStart > mEditText.length() ? mEditText.length() : selectionStart);

啰嗦在最后

好吧,看着这么简单的一个需求被我写出来好几个bug,也是很无奈的说,果然程序员每天的工作就是写bug呀,不管如何,药别停 插一句,最爱婷婷媳妇啦~

你可能感兴趣的:(【bug杂记1】限制EditText文本长度)