当前有个需求.显示一段文本,文本最多显示两行,点击展开后才显示完全。当没有显示完全的时候,需要在文本的第二行末尾显示图标,点击图标和文本,文本展开。
难点在于图标需要和第二行文本显示在同一行,高度和文本一致,居中显示。看似简单 实则思路不好想。最后搞了两天,用html富文本解决。
当中涉及到英文换行的坑 然后涉及到汉字全角 半角导致布局问题的坑。
代码如下
布局文件:
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_margin="10dp"
android:layout_height="match_parent"
android:maxLines="2"
android:ellipsize="end"
android:breakStrategy="balanced"
/>
Activity如下
package com.example.myapplication;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Html;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.ViewTreeObserver;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private String str = "我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱我爱";
private boolean isDeal = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = findViewById(R.id.textView);
textView.setText(toDBC(str));
dealStr(textView);
}
public static String toDBC(String input) {
char[] c = input.toCharArray();
for (int i = 0; i < c.length; i++) {
if (c[i] == 12288) {
// 全角空格为12288,半角空格为32
c[i] = (char) 32;
continue;
}
if (c[i] > 65280 && c[i] < 65375)
// 其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
c[i] = (char) (c[i] - 65248);
}
return new String(c);
}
private void dealStr(TextView textView) {
// 在TextView绘制完成后获取省略的字符数
ViewTreeObserver vto = textView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
if (isDeal) {
return;
}
isDeal = true;
int ellipsisCount = 0;
Layout layout = textView.getLayout();
if (layout != null) {
int lineCount = layout.getLineCount();
if (lineCount > 0) {
int lastLineIndex = lineCount - 1;
// 输出省略的字符数
ellipsisCount = layout.getEllipsisCount(lastLineIndex);
}
}
// 获取文本内容
CharSequence fullText = textView.getText();
if (ellipsisCount > 0) {
// 截断发生
// 获取截断后的文本
CharSequence truncatedText = fullText.subSequence(fullText.length() - ellipsisCount, fullText.length());
CharSequence un_truncatedText = fullText.subSequence(0, fullText.length() - ellipsisCount);
String truncatedString = truncatedText.toString();
replaceStr(textView, un_truncatedText.toString());
} else {
// 没有截断发生
replaceStr(textView, textView.getText().toString());
}
}
});
}
private void replaceStr(TextView textView, String tex) {
SpannableStringBuilder builder = new SpannableStringBuilder();
// 添加HTML文本内容
String htmlText = "<html><body>" + tex + "</body></html>";
builder.append(Html.fromHtml(htmlText));
// 获取Drawable图标
Drawable icon = getResources().getDrawable(R.drawable.expand_icon);
icon.setBounds((int) textView.getTextSize(), 0, icon.getIntrinsicWidth() + (int) textView.getTextSize(), icon.getIntrinsicHeight());
// 创建一个ImageSpan来显示图标
ImageSpan iconSpan = new ImageSpan(icon, ImageSpan.ALIGN_CENTER);
// 将ImageSpan添加到SpannableStringBuilder的末尾
builder.setSpan(iconSpan, builder.length() - 2, builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// 设置TextView的文本内容
textView.setText(builder);
// 垂直居中显示文本和图标
textView.setGravity(Gravity.CENTER_VERTICAL);
}
}