使用TextView显示过长的文字时往往需要省略部分内容,但是TextView控件在maxline>=2时(即多行显示),ellipsize属性只有设置为end才有效,start\middle则无效.因此我们要对此情况进行处理.
处理方式和逻辑见如下代码和注释:
public static void ellipsize(TextView textView, String content) {
TextUtils.TruncateAt ellipsize = textView.getEllipsize();
if (ellipsize != TextUtils.TruncateAt.START && ellipsize != TextUtils.TruncateAt.MIDDLE) { // 只处理start和middle的截断
textView.setText(content);
return;
}
int maxLine = TextViewCompat.getMaxLines(textView);
int availableWidth = textView.getWidth() - textView.getPaddingLeft() - textView.getPaddingRight();
if (maxLine < 2) { // 单行,或没做行数限制
textView.setText(content);
} else {
List<Point> linesStart = getLineStartAndEnd(textView.getPaint(), content, availableWidth);
if (linesStart.size() <= maxLine) { // 行数没有超过限制,不做处理
textView.setText(content);
return;
}
if (ellipsize == TextUtils.TruncateAt.START) {
int start = linesStart.get(linesStart.size() - maxLine).x;
start = Math.max(start + ELLIPSIS_NORMAL.length(), 0);
String substring = content.substring(start);
// 裁剪文字,直到在行数范围内可显示
while (getLayout(textView.getPaint(), ELLIPSIS_NORMAL + substring, availableWidth).getLineCount() > maxLine) {
int firstSpace = substring.indexOf(' '); // 空白字符
if (firstSpace == -1) {
substring = substring.substring(1);
} else {
substring = substring.substring(firstSpace + 1);
}
}
textView.setText(ELLIPSIS_NORMAL + substring);
} else { // middle
int middleLineStart = (maxLine - 1) / 2;
Point point = linesStart.get(middleLineStart);
int startEllipsize = point.y - ELLIPSIS_NORMAL.length();// 在中间行的末尾追加省略号
final String substringStart = content.substring(0, startEllipsize); // 省略号前面的文字
int middleLineEnd = linesStart.size() - (maxLine - (maxLine - 1) / 2 - 1);
Point pointEnd = linesStart.get(middleLineEnd);
String substringEnd = content.substring(pointEnd.x);
// 裁剪省略号后面的文字,直到整体在行数范围内可显示
while (getLayout(textView.getPaint(), substringStart + ELLIPSIS_NORMAL + substringEnd, availableWidth).getLineCount() > maxLine) {
int firstSpace = substringEnd.indexOf(' '); // 空白字符
if (firstSpace == -1) {
substringEnd = substringEnd.substring(1);
} else {
substringEnd = substringEnd.substring(firstSpace + 1);
}
}
textView.setText(substringStart + ELLIPSIS_NORMAL + substringEnd);
}
}
}
/**
* 计算每一行的开始字符位置和结束字符位置
* @return List.size()为总行数.point.x 为当前行的开始字符位置, point.y 为当前行的结束字符位置
*/
private static List<Point> getLineStartAndEnd(TextPaint tp, CharSequence cs, int lineWidth) {
// StaticLayout是android中处理文字换行的一个工具类,StaticLayout已经实现了文本绘制换行处理
StaticLayout layout = new StaticLayout(cs, tp, lineWidth, Layout.Alignment.ALIGN_NORMAL,
1.0f, 0.0f, true);
int count = layout.getLineCount();
List<Point> list = new ArrayList<>();
for (int i = 0; i < count; i++) {
list.add(new Point(layout.getLineStart(i), layout.getLineEnd(i)));
}
return list;
}
效果
![](https://img.haomeiwen.com/i10211118/5266397abab7fd65.png)
github
完整代码封装在github上的Androids项目中的EllipsizeUtils类中.
Androids项目是本人根据平时的项目实践经验,为了提高Android开发效率而写的一个工具SDK;里面提供了一些工具类以及自定义View,可在实际项目开发时直接使用。
谢谢大家支持!
网友评论