135 lines
3.9 KiB
Java
135 lines
3.9 KiB
Java
package com.uiuios.aios.view;
|
||
|
||
import android.content.Context;
|
||
import android.graphics.Rect;
|
||
import android.text.Layout;
|
||
import android.text.StaticLayout;
|
||
import android.util.AttributeSet;
|
||
|
||
import androidx.annotation.Nullable;
|
||
import androidx.appcompat.widget.AppCompatTextView;
|
||
|
||
public class ExpandTextView extends AppCompatTextView {
|
||
/**
|
||
* true:展开,false:收起
|
||
*/
|
||
boolean mExpanded;
|
||
/**
|
||
* 状态回调
|
||
*/
|
||
Callback mCallback;
|
||
/**
|
||
* 源文字内容
|
||
*/
|
||
String mText = "";
|
||
/**
|
||
* 最多展示的行数
|
||
*/
|
||
final int maxLineCount = 3;
|
||
/**
|
||
* 省略文字
|
||
*/
|
||
final String ellipsizeText = "...";
|
||
|
||
public ExpandTextView(Context context, @Nullable AttributeSet attrs) {
|
||
super(context, attrs);
|
||
}
|
||
|
||
@Override
|
||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||
// 文字计算辅助工具
|
||
StaticLayout sl = new StaticLayout(mText, getPaint(), getMeasuredWidth() - getPaddingLeft() - getPaddingRight()
|
||
, Layout.Alignment.ALIGN_CENTER, 1, 0, true);
|
||
// 总计行数
|
||
int lineCount = sl.getLineCount();
|
||
if (lineCount > maxLineCount) {
|
||
if (mExpanded) {
|
||
setText(mText);
|
||
mCallback.onExpand();
|
||
} else {
|
||
lineCount = maxLineCount;
|
||
|
||
// 省略文字的宽度
|
||
float dotWidth = getPaint().measureText(ellipsizeText);
|
||
|
||
// 找出第 showLineCount 行的文字
|
||
int start = sl.getLineStart(lineCount - 1);
|
||
int end = sl.getLineEnd(lineCount - 1);
|
||
String lineText = mText.substring(start, end);
|
||
|
||
// 将第 showLineCount 行最后的文字替换为 ellipsizeText
|
||
int endIndex = 0;
|
||
for (int i = lineText.length() - 1; i >= 0; i--) {
|
||
String str = lineText.substring(i, lineText.length());
|
||
// 找出文字宽度大于 ellipsizeText 的字符
|
||
if (getPaint().measureText(str) >= dotWidth) {
|
||
endIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 新的第 showLineCount 的文字
|
||
String newEndLineText = lineText.substring(0, endIndex) + ellipsizeText;
|
||
// 最终显示的文字
|
||
setText(mText.substring(0, start) + newEndLineText);
|
||
|
||
mCallback.onCollapse();
|
||
}
|
||
} else {
|
||
setText(mText);
|
||
mCallback.onLoss();
|
||
}
|
||
|
||
// 重新计算高度
|
||
int lineHeight = 0;
|
||
for (int i = 0; i < lineCount; i++) {
|
||
Rect lineBound = new Rect();
|
||
sl.getLineBounds(i, lineBound);
|
||
lineHeight += lineBound.height();
|
||
}
|
||
lineHeight += getPaddingTop() + getPaddingBottom();
|
||
setMeasuredDimension(getMeasuredWidth(), lineHeight);
|
||
}
|
||
|
||
/**
|
||
* 设置要显示的文字以及状态
|
||
* @param text
|
||
* @param expanded true:展开,false:收起
|
||
* @param callback
|
||
*/
|
||
public void setText(String text, boolean expanded, Callback callback) {
|
||
mText = text;
|
||
mExpanded = expanded;
|
||
mCallback = callback;
|
||
|
||
// 设置要显示的文字,这一行必须要,否则 onMeasure 宽度测量不正确
|
||
setText(text);
|
||
}
|
||
|
||
/**
|
||
* 展开收起状态变化
|
||
* @param expanded
|
||
*/
|
||
public void setChanged(boolean expanded) {
|
||
mExpanded = expanded;
|
||
requestLayout();
|
||
}
|
||
|
||
public interface Callback {
|
||
/**
|
||
* 展开状态
|
||
*/
|
||
void onExpand();
|
||
|
||
/**
|
||
* 收起状态
|
||
*/
|
||
void onCollapse();
|
||
|
||
/**
|
||
* 行数小于最小行数,不满足展开或者收起条件
|
||
*/
|
||
void onLoss();
|
||
}
|
||
} |