参考自他人https://blog.csdn.net/Luckly452468460/article/details/103613471 通过自己实现CreateAppenderListener,可以自己定义 尾部追加的文字或者图片,或者文字加图片。 有注释,就不解释细节了。 使用: 折叠状态: 展开状态:
<com.example.myapplication.ExpandTextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="4" />
expandTextView.init(false, text, null);
expandTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
expandTextView.toggle();
}
});
实现:
package com.example.myapplication;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Layout;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.method.LinkMovementMethod;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import androidx.annotation.Nullable;
public class ExpandTextView extends androidx.appcompat.widget.AppCompatTextView {
private String originText;
private int mWidth = Integer.MAX_VALUE;
private int mMaxLines = 0;
private SpannableString SPAN_TO_EXPAND = null;
private SpannableString SPAN_TO_CLOSE = null;
private boolean ToDBC = true;
private boolean mIsExpanding = false;
private int mOriginTextLines;
private int mToExpandImageWidth = 0;
private int mToCloseImageWidth = 0;
public ExpandTextView(Context context) {
super(context);
}
public ExpandTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpandTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void init(boolean toExpand, String text, @Nullable CreateAppenderListener createAppenderListener) {
mMaxLines = getMaxLines();
originText = ToDBC ? ToDBC(text) : toDBC(text);
if (createAppenderListener != null) {
SPAN_TO_CLOSE = createAppenderListener.getDefaultToCloseSpannableString();
SPAN_TO_EXPAND = createAppenderListener.getDefaultToExpandSpannableString();
} else {
SPAN_TO_CLOSE = getDefaultToCloseSpannableString();
SPAN_TO_EXPAND = getDefaultToExpandSpannableString();
}
mOriginTextLines = createWorkingLayout(originText).getLineCount();
toggle(toExpand);
}
public void toggle(boolean toExpand) {
post(new Runnable() {
@Override
public void run() {
mWidth = getWidth();
if (toExpand) {
setExpandText();
} else {
setCloseText();
}
}
});
}
public void toggle() {
if (mIsExpanding) {
toggle(false);
} else {
toggle(true);
}
}
@Override
public void setMaxLines(int maxLines) {
if (mMaxLines == 0) {
this.mMaxLines = maxLines;
}
super.setMaxLines(maxLines);
}
public void setToDBC(boolean toDBC) {
ToDBC = toDBC;
}
public int getToExpandImageWidth() {
return mToExpandImageWidth;
}
public int getToCloseImageWidth() {
return mToCloseImageWidth;
}
public void setToExpandImageWidth(int mToExpandImageWidth) {
this.mToExpandImageWidth = mToExpandImageWidth;
}
public void setToCloseImageWidth(int mToCloseImageWidth) {
this.mToCloseImageWidth = mToCloseImageWidth;
}
public SpannableString getDefaultToExpandSpannableString() {
SpannableString spannableString = new SpannableString("... ");
Paint paint = getPaint();
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
setToExpandImageWidth((int) (fontMetrics.descent - fontMetrics.ascent));
Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher);
drawable.setBounds(0, 0 , getToExpandImageWidth(), getToExpandImageWidth());
ImageSpan span = new ImageSpan(drawable);
spannableString.setSpan(span, spannableString.length() - 1, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
return spannableString;
}
public SpannableString getDefaultToCloseSpannableString() {
SpannableString spannableString = new SpannableString(" ");
Paint paint = getPaint();
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
setToCloseImageWidth((int) (fontMetrics.descent - fontMetrics.ascent));
Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher);
drawable.setBounds(0, 0 , getToCloseImageWidth(), getToCloseImageWidth());
ImageSpan span = new ImageSpan(drawable);
spannableString.setSpan(span, spannableString.length() - 1, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
return spannableString;
}
public void setCloseText() {
mIsExpanding = false;
setMaxLines(mMaxLines);
boolean needAppend = false;
String workingText = originText;
if (mMaxLines != 0) {
Layout originLayout = createWorkingLayout(originText);
mOriginTextLines = originLayout.getLineCount();
if (mOriginTextLines > mMaxLines) {
workingText = originText.substring(0, originLayout.getLineEnd(mMaxLines - 1)).trim();
float allWidth = getPaint().measureText(workingText);
float realWidth = getPaint().measureText(workingText + SPAN_TO_EXPAND) + mToExpandImageWidth;
while (realWidth > allWidth) {
int lastSpace = workingText.length() - 1;
if (lastSpace == -1) {
break;
}
workingText = workingText.substring(0, lastSpace);
realWidth = getPaint().measureText(workingText + SPAN_TO_EXPAND) + mToExpandImageWidth;
}
needAppend = true;
}
}
setText(workingText);
if (needAppend) {
append(SPAN_TO_EXPAND);
}
setMovementMethod(LinkMovementMethod.getInstance());
}
public void setExpandText() {
if (mOriginTextLines <= mMaxLines) {
return;
}
mIsExpanding = true;
setMaxLines(Integer.MAX_VALUE);
Layout originLayout = createWorkingLayout(originText);
Layout compareLayout = createWorkingLayout(originText + SPAN_TO_CLOSE);
if (compareLayout.getLineCount() > originLayout.getLineCount()) {
setText(originText + "\n");
} else {
setText(originText);
}
append(SPAN_TO_CLOSE);
setMovementMethod(LinkMovementMethod.getInstance());
}
private Layout createWorkingLayout(String workingText) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
return StaticLayout.Builder.obtain(workingText, 0, workingText.length(), getPaint(), mWidth).build();
} else {
return new StaticLayout(workingText, getPaint(), mWidth - getPaddingLeft() - getPaddingRight(),
Layout.Alignment.ALIGN_NORMAL, getLineSpacingMultiplier(), getLineSpacingExtra(), false);
}
}
@Override
public void setLongClickable(boolean longClickable) {
super.setLongClickable(false);
}
private static String toDBC(String input) {
char[] c = input.toCharArray();
for (int i = 0; i < c.length; i++) {
if (c[i] == '\n') {
} else if (c[i] == ' ') {
c[i] = '\u3000';
} else if (c[i] < '\177') {
c[i] = (char) (c[i] + 65248);
}
}
return new String(c);
}
public static String ToDBC(String input) {
char[] c = input.toCharArray();
for (int i = 0; i < c.length; i++) {
if (c[i] == '\u3000') {
c[i] = ' ';
} else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {
c[i] = (char) (c[i] - 65248);
}
}
return new String(c);
}
public interface CreateAppenderListener {
SpannableString getDefaultToCloseSpannableString();
SpannableString getDefaultToExpandSpannableString();
}
}
|