問題
我們還是從問題開始說起,在開發(fā)中我們經(jīng)常會用到TextView顯示文本,并根據(jù)產(chǎn)品要求顯示為單行或者是規(guī)定的幾行,超出部分顯示為省略號的需求。最近在做這個需求的時候,發(fā)現(xiàn)了一些問題,在這里記錄一下。
實現(xiàn)
在這個需求上,我們一般都是這樣寫:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true" />
但是這樣編譯器會有一個這樣的提示:

由于google給的提示,我們會欣然接受,將singleLine改為了maxLines="1",那么問題就出現(xiàn)了。
效果
通過maxLines="1"設(shè)置后,顯示在手機上的文案就會發(fā)現(xiàn)顯示不完全的問題,例如:hello world!
可能只顯示了hello world或者hello,而省略號完全沒有,再例如:“你好世界”可能顯示為“你好世”,而在我的項目里有過這樣的情況,就是“(你好,世界)”,最后面的一半括號沒了,顯示為“(你好,世界”。
原因
問題說完了,看一下是什么導致的。


maxLines:對行的高度進行限制,并不會影響顯示的換行規(guī)則,顯示不完則不顯示
singleLine:限制在一行顯示,如果顯示不完則會顯示省略號
如果將省略號設(shè)置在中間位置,則maxLines無效。
TextView內(nèi)部輔助類:
1、BoringLayout 主要負責顯示單行文本,并提供了isBoring方法來判斷是否滿足單行文本的條件。
2、DynamicLayout當文本為Spannable的時候,TextView就會使用它來負責文本的顯示,在內(nèi)部設(shè)置了SpanWatcher,當檢測到span改變的時候,會進行reflow,重新計算布局。
3、StaticLayout當文本為非單行文本,且非Spannable的時候,就會使用StaticLayout,內(nèi)部并不會監(jiān)聽span的變化,因此效率上會比DynamicLayout高,只需一次布局的創(chuàng)建即可,但其實內(nèi)部也能顯示SpannableString,只是不能在span變化之后重新進行布局而已。
TextView的折行包含以下規(guī)律:
1、半角字符與全角字符混亂所致:這種情況一般就是漢字與數(shù)字、英文字母混用。
2、TextView在顯示中文的時候標點符號不能顯示在一行的行首和行尾,如果一個標點符號剛好在一行的行尾,該標點符號就會連同前一個字符跳到下一行顯示。
3、一個英文單詞不能被顯示在兩行中( TextView在顯示英文時,標點符號是可以放在行尾的,但英文單詞也不能分開 )。
StaticLayout中針對ellipsize屬性,對文本內(nèi)容單獨進行了處理(之前的折行處理效果在這里就不管用了),然后Layout.onDraw的時候只會繪制處理完后的text。
建議
如果為了實現(xiàn)顯示省略號的效果,建議使用singleLine。
如果單獨是為了限制行數(shù),建議使用maxLines
延伸
實現(xiàn)省略號的效果時,如果要求顯示超過幾個字符后,顯示省略號,可以在代碼中進行設(shè)置:
String string = "hello world!";
if(string.length() > index) {
String subString = string.substring(0, index);
string = subString + "…";
}
這種方式在使用android:maxLength="index"或者android:maxEms="index"效果不好的時候使用。
這個效果不好就是使用maxLength沒有省略號的效果,使用maxEms顯示的字符數(shù)和要求的有差別,具體原因具體分析。