问题
我们还是从问题开始说起,在开发中我们经常会用到TextView显示文本,并根据产品要求显示为单行或者是规定的几行,超出部分显示为省略号的需求。最近在做这个需求的时候,发现了一些问题,在这里记录一下。
实现
在这个需求上,我们一般都是这样写:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true" />
但是这样编译器会有一个这样的提示:
image.png由于google给的提示,我们会欣然接受,将singleLine改为了maxLines="1",那么问题就出现了。
效果
通过maxLines="1"设置后,显示在手机上的文案就会发现显示不完全的问题,例如:hello world!
可能只显示了hello world或者hello,而省略号完全没有,再例如:“你好世界”可能显示为“你好世”,而在我的项目里有过这样的情况,就是“(你好,世界)”,最后面的一半括号没了,显示为“(你好,世界”。
原因
问题说完了,看一下是什么导致的。
maxLines singleLinemaxLines:对行的高度进行限制,并不会影响显示的换行规则,显示不完则不显示
singleLine:限制在一行显示,如果显示不完则会显示省略号
如果将省略号设置在中间位置,则maxLines无效。
TextView内部辅助类:
1、BoringLayout 主要负责显示单行文本,并提供了isBoring方法来判断是否满足单行文本的条件。
2、DynamicLayout当文本为Spannable的时候,TextView就会使用它来负责文本的显示,在内部设置了SpanWatcher,当检测到span改变的时候,会进行reflow,重新计算布局。
3、StaticLayout当文本为非单行文本,且非Spannable的时候,就会使用StaticLayout,内部并不会监听span的变化,因此效率上会比DynamicLayout高,只需一次布局的创建即可,但其实内部也能显示SpannableString,只是不能在span变化之后重新进行布局而已。
TextView的折行包含以下规律:
1、半角字符与全角字符混乱所致:这种情况一般就是汉字与数字、英文字母混用。
2、TextView在显示中文的时候标点符号不能显示在一行的行首和行尾,如果一个标点符号刚好在一行的行尾,该标点符号就会连同前一个字符跳到下一行显示。
3、一个英文单词不能被显示在两行中( TextView在显示英文时,标点符号是可以放在行尾的,但英文单词也不能分开 )。
StaticLayout中针对ellipsize属性,对文本内容单独进行了处理(之前的折行处理效果在这里就不管用了),然后Layout.onDraw的时候只会绘制处理完后的text。
建议
如果为了实现显示省略号的效果,建议使用singleLine。
如果单独是为了限制行数,建议使用maxLines
延伸
实现省略号的效果时,如果要求显示超过几个字符后,显示省略号,可以在代码中进行设置:
String string = "hello world!";
if(string.length() > index) {
String subString = string.substring(0, index);
string = subString + "…";
}
这种方式在使用android:maxLength="index"或者android:maxEms="index"效果不好的时候使用。
这个效果不好就是使用maxLength没有省略号的效果,使用maxEms显示的字符数和要求的有差别,具体原因具体分析。
网友评论