我到底想要干啥?
需求的本意是EditText只能輸入不超過一行的文字并且不會出現(xiàn)"…",所以簡單使用singleLine來實(shí)現(xiàn)這個效果肯定不行绰筛,那么下一個思路就是通過添加TextWatcher對文本變化進(jìn)行監(jiān)聽,并且通過不斷measure文字的寬度并且不斷截取文字來使文字短到可以被控件顯示下,所以使用substring來實(shí)現(xiàn)這個需求爹袁,重點(diǎn)就在截取文字的代碼,所以我的第一版本是醬紫的
簡單實(shí)現(xiàn)V0.9
public String adjustText(TextView textView, String text) {
String tmpTxt = null;
// 要求只能顯示一行的文字寬度不能換行
if (textView != null && text != null) {
// 為了避免substring刪除emoji等多個char的元素導(dǎo)致的錯誤截取
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;
}
簡單測試了試了幾次矮固,輸入中文或者英文字符乍一看是沒有問題的失息,結(jié)果為了賣萌輸入了??這個emoji表情,就出現(xiàn)了亂碼档址,納尼盹兢?什么鬼〕皆危可是到底是歪?
為啥用substring之后就亂碼了呢蛤迎?
原來Java對于普通的字符char使用2個字節(jié)存儲,而中文和emoji等使用2個char(4字節(jié))存儲含友,但是substring是直接截取是針對單個char的替裆,直接把emoji的char給人家截?cái)嗔诵1纾?dāng)然就顯示亂碼嘍~
怎么解決亂碼問題呢?
原因知道了辆童,可是怎么解決呢宜咒。原來Java早就考慮到這種問題啦,通過codePointCount可以獲取有效的代碼點(diǎn)把鉴。啥是代碼點(diǎn)故黑,理解為一個完整的字符(可能1個char,也可能2個char)庭砍,比如一個emoji表情就認(rèn)為是一個代碼點(diǎn)场晶,通過offsetByCodePoints可以獲取第i個代碼點(diǎn)距離其實(shí)下標(biāo)的距離,通過substring就可以獲取正確的字符串啦怠缸,就不存在截取一半emoji的尷尬情況啦诗轻,整理下,代碼如下~
簡單實(shí)現(xiàn)V1.0
public String adjustText(TextView textView, String text) {
String tmpTxt = null;
// 要求只能顯示一行的文字寬度不能換行
if (textView != null && text != null) {
// 為了避免substring刪除emoji等多個char的元素導(dǎo)致的錯誤截取
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方法中調(diào)用EditText的setText來實(shí)現(xiàn)截劝饩妗(注意設(shè)置前一定要比較當(dāng)前的文本和設(shè)置的文本哦,不然就要StackOverFlow啦)搔体,尷尬的是又存在了另一個問題恨樟,就是光標(biāo)問題呀,不能每次截取都要把光標(biāo)移到最后面吧疚俱。所以通過設(shè)置前備份下光標(biāo)位置即可劝术,代碼如下
int selectionStart = mEditText.getSelectionStart();
mEditText.setText(handledText);
mEditText
.setSelection(selectionStart > mEditText.length() ? mEditText.length() : selectionStart);
啰嗦在最后
好吧,看著這么簡單的一個需求被我寫出來好幾個bug计螺,也是很無奈的說夯尽,果然程序員每天的工作就是寫bug呀,不管如何登馒,藥別停 插一句匙握,最愛婷婷媳婦啦~