有一個(gè)需求
當(dāng)一個(gè)文本過長的時(shí)候會(huì)顯示很多行,為了顯示更多的信息(露出更多的view),會(huì)出現(xiàn)查看更多的需求。類似于下圖:

半行顯示查看更多
有一個(gè)想法
因?yàn)槭窃赥extView內(nèi)部處理這個(gè)事,所以一定要自定義TextView,把新的TextView叫做TailTextView。
大致思路如下:
- 先使用maxLines屬性將TextView的理想高度測量出來
- 找到最后一行字母的位置,加上查看更多,再加個(gè)顏色,調(diào)用一下回調(diào)方法
- 重新使用setText,將新的CharSequence設(shè)置進(jìn)去
做一個(gè)實(shí)現(xiàn)
自定義屬性寫了兩個(gè):showTail(是否顯示小尾巴)和tailColor(尾巴顏色)
重寫onMeasure方法,先使用super的測量方法得到TextView每一行的布局
拿到TextView前maxLines-1行的文字,作為一定顯示的文字,最后一行作為要處理的文字
測量出小尾巴的寬度,將一行最大的寬度減去小尾巴寬度,得到原來文字最大寬度,使用這個(gè)寬度對(duì)最后一行文字進(jìn)行裁切。
在剛才得到的文字上加上“…查看更多”,設(shè)置span,回調(diào)被裁切方法。
將新的Text重新設(shè)置到TextView上。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//不顯示小尾巴或者已經(jīng)處理過的不再處理
if (!showTail || mEllipsizeFinal) {
return;
}
int lineCount = getLineCount();
Layout layout = getLayout();
int maxLines = getMaxLines();
//行數(shù)沒有到maxLines不處理
if (maxLines == 0 || lineCount < maxLines || TextUtils.isEmpty(getText())){
return;
}
//一共的文字?jǐn)?shù)量
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());
//最后一個(gè)字是個(gè)換行符就把這個(gè)換行符去掉,不然不能在那一行后面增加文字了
if (LINE_BREAKER.equals(String.valueOf(getText().charAt(totalChars - 1)))) {
lastLineText = getText().subSequence(lastLineStartIndex, totalChars - 1);
} else {
lastLineText = getText().subSequence(lastLineStartIndex, totalChars);
}
//這里可能會(huì)出現(xiàn)每一行都有換行符,然后整個(gè)TextView的寬度很小的情況
//對(duì)可能超過右邊進(jìn)行修正,screenWidth * 0.6f是應(yīng)該可以調(diào)整的
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);
//重新設(shè)置文本
super.setText(spannableStringBuilder);
//每設(shè)置一次text要重置一個(gè)這個(gè)位。重寫setText(在里面重新置位)
mEllipsizeFinal = true;
onEllipsize();//回調(diào)是否被裁切
}
效果就是上面放的圖了。
寫一些Tips
設(shè)置maxLines屬性之后就不要設(shè)置ellipsize="end"了,可能會(huì)引起最后一行的寬度測量不準(zhǔn)確。
screenWidth * 0.6f有點(diǎn)草率,可以修改的
如果要使用原來的maxLines屬性的功能就設(shè)置showTail為false
沒有給出TailTextView的全文,但核心內(nèi)容就是這些了