我到底想要干啥?
需求的本意是EditText只能輸入不超過(guò)一行的文字并且不會(huì)出現(xiàn)"…",所以簡(jiǎn)單使用singleLine來(lái)實(shí)現(xiàn)這個(gè)效果肯定不行,那么下一個(gè)思路就是通過(guò)添加TextWatcher對(duì)文本變化進(jìn)行監(jiān)聽(tīng),并且通過(guò)不斷measure文字的寬度并且不斷截取文字來(lái)使文字短到可以被控件顯示下,所以使用substring來(lái)實(shí)現(xiàn)這個(gè)需求,重點(diǎn)就在截取文字的代碼,所以我的第一版本是醬紫的
簡(jiǎn)單實(shí)現(xiàn)V0.9
public String adjustText(TextView textView, String text) {
String tmpTxt = null;
// 要求只能顯示一行的文字寬度不能換行
if (textView != null && text != null) {
// 為了避免substring刪除emoji等多個(gè)char的元素導(dǎo)致的錯(cuò)誤截取
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ǎn)單測(cè)試了試了幾次,輸入中文或者英文字符乍一看是沒(méi)有問(wèn)題的,結(jié)果為了賣萌輸入了??這個(gè)emoji表情,就出現(xiàn)了亂碼,納尼?什么鬼??墒堑降资峭?
為啥用substring之后就亂碼了呢?
原來(lái)Java對(duì)于普通的字符char使用2個(gè)字節(jié)存儲(chǔ),而中文和emoji等使用2個(gè)char(4字節(jié))存儲(chǔ),但是substring是直接截取是針對(duì)單個(gè)char的,直接把emoji的char給人家截?cái)嗔?,?dāng)然就顯示亂碼嘍~
怎么解決亂碼問(wèn)題呢?
原因知道了,可是怎么解決呢。原來(lái)Java早就考慮到這種問(wèn)題啦,通過(guò)codePointCount可以獲取有效的代碼點(diǎn)。啥是代碼點(diǎn),理解為一個(gè)完整的字符(可能1個(gè)char,也可能2個(gè)char),比如一個(gè)emoji表情就認(rèn)為是一個(gè)代碼點(diǎn),通過(guò)offsetByCodePoints可以獲取第i個(gè)代碼點(diǎn)距離其實(shí)下標(biāo)的距離,通過(guò)substring就可以獲取正確的字符串啦,就不存在截取一半emoji的尷尬情況啦,整理下,代碼如下~
簡(jiǎn)單實(shí)現(xiàn)V1.0
public String adjustText(TextView textView, String text) {
String tmpTxt = null;
// 要求只能顯示一行的文字寬度不能換行
if (textView != null && text != null) {
// 為了避免substring刪除emoji等多個(gè)char的元素導(dǎo)致的錯(cuò)誤截取
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;
}
這個(gè)情況處理完畢,處理完字符串的截取在onTextChanged方法中調(diào)用EditText的setText來(lái)實(shí)現(xiàn)截取(注意設(shè)置前一定要比較當(dāng)前的文本和設(shè)置的文本哦,不然就要StackOverFlow啦),尷尬的是又存在了另一個(gè)問(wèn)題,就是光標(biāo)問(wèn)題呀,不能每次截取都要把光標(biāo)移到最后面吧。所以通過(guò)設(shè)置前備份下光標(biāo)位置即可,代碼如下
int selectionStart = mEditText.getSelectionStart();
mEditText.setText(handledText);
mEditText
.setSelection(selectionStart > mEditText.length() ? mEditText.length() : selectionStart);
啰嗦在最后
好吧,看著這么簡(jiǎn)單的一個(gè)需求被我寫出來(lái)好幾個(gè)bug,也是很無(wú)奈的說(shuō),果然程序員每天的工作就是寫bug呀,不管如何,藥別停 插一句,最愛(ài)婷婷媳婦啦~