有一个需求
当一个文本过长的时候会显示很多行,为了显示更多的信息(露出更多的view),会出现查看更多的需求。类似于下图:
有一个想法
因为是在TextView内部处理这个事,所以一定要自定义TextView,把新的TextView叫做TailTextView。
大致思路如下:
- 先使用maxLines属性将TextView的理想高度测量出来
- 找到最后一行字母的位置,加上查看更多,再加个颜色,调用一下回调方法
- 重新使用setText,将新的CharSequence设置进去
做一个实现
自定义属性写了两个:showTail(是否显示小尾巴)和tailColor(尾巴颜色)
重写onMeasure方法,先使用super的测量方法得到TextView每一行的布局
拿到TextView前maxLines-1行的文字,作为一定显示的文字,最后一行作为要处理的文字
测量出小尾巴的宽度,将一行最大的宽度减去小尾巴宽度,得到原来文字最大宽度,使用这个宽度对最后一行文字进行裁切。
在刚才得到的文字上加上“…查看更多”,设置span,回调被裁切方法。
将新的Text重新设置到TextView上。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//不显示小尾巴或者已经处理过的不再处理
if (!showTail || mEllipsizeFinal) {
return;
}
int lineCount = getLineCount();
Layout layout = getLayout();
int maxLines = getMaxLines();
//行数没有到maxLines不处理
if (maxLines == 0 || lineCount < maxLines || TextUtils.isEmpty(getText())){
return;
}
//一共的文字数量
int totalChars = layout.getLineEnd(maxLines - 1);
int lastLineStartIndex = layout.getLineStart(maxLines - 1);
if (totalChars >= getText().length()) {
return;
}
CharSequence mustShowText = getText().subSequence(0, lastLineStartIndex);
String tailText = "…查看全文";
float tailWidth = getPaint().measureText(tailText);
CharSequence lastLineText;
int screenWidth = DeviceUtils.getScreenWidth(getContext());
//最后一个字是个换行符就把这个换行符去掉,不然不能在那一行后面增加文字了
if (LINE_BREAKER.equals(String.valueOf(getText().charAt(totalChars - 1)))) {
lastLineText = getText().subSequence(lastLineStartIndex, totalChars - 1);
} else {
lastLineText = getText().subSequence(lastLineStartIndex, totalChars);
}
//这里可能会出现每一行都有换行符,然后整个TextView的宽度很小的情况
//对可能超过右边进行修正,screenWidth * 0.6f是应该可以调整的
float maxWidth = Math.max(screenWidth * 0.6f, getMeasuredWidth());
CharSequence ellipsizeLastLineText = TextUtils.ellipsize(lastLineText, getPaint(), maxWidth - tailWidth,
TextUtils.TruncateAt.END);
if (ellipsizeLastLineText.length() > 2 && ellipsizeLastLineText != lastLineText) {
lastLineText = ellipsizeLastLineText.subSequence(0, ellipsizeLastLineText.length() - 1);
}
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(mustShowText);
spannableStringBuilder.append(lastLineText);
int start = spannableStringBuilder.length();
spannableStringBuilder.append(tailText);
spannableStringBuilder.setSpan(new ForegroundColorSpan(tailColor), start + 1, start + 5,
Spannable.SPAN_INCLUSIVE_INCLUSIVE);
//重新设置文本
super.setText(spannableStringBuilder);
//每设置一次text要重置一个这个位。重写setText(在里面重新置位)
mEllipsizeFinal = true;
onEllipsize();//回调是否被裁切
}
效果就是上面放的图了。
写一些Tips
设置maxLines属性之后就不要设置ellipsize="end"了,可能会引起最后一行的宽度测量不准确。
screenWidth * 0.6f有点草率,可以修改的
如果要使用原来的maxLines属性的功能就设置showTail为false
没有给出TailTextView的全文,但核心内容就是这些了