一、情景再现
当TextView的高度宽度为固定大小时,随着其Text的动态增加,导致TextView的显示范围以无法满足完全显示所有Text时,这个时候TextView会直接不显示后面动态增加的文字,这个时候我们很可能其实是想显示后面动态增加的文字,那么这个时候我们就需要计算该TextView可以显示的文字范围,然后动态的显示我们需要显示的某一范围的文字。
例如,有一个动态文字:端午节可以去你家吃粽子吗?我可以帮你跑8公里
我们没有处理前,可能是这样动态显示:
可以看到当我们增加了第二句话之后,TextView已经无法显示完整了,导致看不到第二句话。
处理后我们可以选择某个范围,例如可能之前我们已经看到了前面的文字,只想显示后面的:
二、实现原理
那么上面的 功能是如何实现的呢?接下来我们来分析下:
假如这是一个TextView,当然实际中,还没显示文字的时候我们是不知道它有能力显示多少行的
如果我们要想知道这个TextView可以显示多少个文字,只需要计算TextView显示的总宽度,文字的宽度,当文字的宽度大于TextView显示的总宽度时,通过取文本区间,得以按照你想要的文本显示在TextView上
那么,我们怎么接着看看怎么计算TextView可以显示的总宽度和文本的宽度:
1.首先我们得计算TextView 单行的宽度,viewWidth
private int lineHeight=0;
private int viewHeight=0;
private int viewWidth=0;
private int maxLine=0;
private int totalWidth=0;
viewWidth = textView.getMeasuredWidth();
2.计算TextView可以显示多少行 maxLine,通过 总高度/行高,
viewHeight = textView..getMeasuredHeight();
lineHeight = textView..getLineHeight();
maxLine = viewHeight/lineHeight;
textView.setMaxLines(maxLine);
3.接着得到总宽度
totalWidth = viewWidth * maxLine ;
4.计算文本的宽度
TextPaint textPaint = textView.getPaint();
float textPaintWidth = textPaint.measureText(text);
5.接着就是按照你自己想要显示的方式递归计算最终需要显示的结果即可,例如我这里同构先进先出计算显示的文字,得到如下递归函数,其他的显示需求读者自己举一反三,自由发挥。
public String calculateTextPreScreen(String tempStr, TextPaint textPaint, int width) {
if (tempStr == null) {
return "";
}
float textPaintWidth = textPaint.measureText(tempStr);
if (textPaintWidth > width) {
for (int i = 1; i < tempStr.length(); i++) {
String tempSubStr = tempStr.substring(i, tempStr.length());
return calculateTextPreScreen(tempSubStr, textPaint, width);
}
}
return tempStr;
}
最后需要注意的是,TextView的高度和宽度需要在View绘制完成之后才能获取,通过如下方式:
textView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (viewHeight!=0){
viewWidth = textViewgetMeasuredWidth();
viewHeight = textView.getMeasuredHeight();
lineHeight = textView.getLineHeight();
maxLine = viewHeight/lineHeight;
totalWidth = viewWidth * maxLine ;
textView.setMaxLines(maxLine);
textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});