【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來實現截?。ㄗ⒁庠O置前一定要比較當前的文本和設置的文本哦,不然就要StackOverFlow啦),尷尬的是又存在了另一個問題,就是光標問題呀,不能每次截取都要把光標移到最后面吧。所以通過設置前備份下光標位置即可,代碼如下

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

啰嗦在最后

好吧,看著這么簡單的一個需求被我寫出來好幾個bug,也是很無奈的說,果然程序員每天的工作就是寫bug呀,不管如何,藥別停 插一句,最愛婷婷媳婦啦~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容