Android TextView使用AbsoluteSizeSpan时自动换行行高异常如何解决?
问题原因
Android 系统默认计算 TextView 段落行高时,会以整个段落内所有文本的最大字号作为基准,不会根据每行实际包含的文本 Span 大小动态调整行高。手动插入\n时相当于拆分了两个独立段落,所以第二段可以单独计算适配自身的行高;自动换行时所有文本属于同一个段落,因此所有行都会统一使用全段落最大字号对应的行高。
解决方案
方案1:自定义LineHeightSpan动态计算每行高度(全版本兼容)
通过自定义实现LineHeightSpan,重写行高计算逻辑,遍历当前行的所有文本 Span,取实际最大字号作为该行行高的计算基准。
自定义Span代码:
public class DynamicLineHeightSpan implements LineHeightSpan { private final int defaultTextSize; // 构造传入TextView默认字号 public DynamicLineHeightSpan(int defaultTextSize) { this.defaultTextSize = defaultTextSize; } @Override public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int lineHeight, Paint.FontMetricsInt fm) { Spanned spanned = (Spanned) text; int maxTextSize = 0; // 遍历当前行所有AbsoluteSizeSpan,获取最大字号 AbsoluteSizeSpan[] sizeSpans = spanned.getSpans(start, end, AbsoluteSizeSpan.class); for (AbsoluteSizeSpan span : sizeSpans) { maxTextSize = Math.max(maxTextSize, span.getSize()); } // 无特殊字号时用默认字号计算 maxTextSize = maxTextSize == 0 ? defaultTextSize : maxTextSize; // 重新计算适配当前行的行高参数 Paint paint = new Paint(); paint.setTextSize(maxTextSize); Paint.FontMetricsInt lineFm = paint.getFontMetricsInt(); fm.ascent = lineFm.ascent; fm.descent = lineFm.descent; fm.top = lineFm.top; fm.bottom = lineFm.bottom; } }
使用方式:
String text = "And here's to you, Mrs. Robinson Jesus loves you more than you will know"; final SpannableStringBuilder styled = new SpannableStringBuilder(text); AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(40); styled.setSpan(sizeSpan, 24, 32, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // 添加动态行高Span到整个文本范围 styled.setSpan(new DynamicLineHeightSpan((int) tv.getTextSize()), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); tv.setText(styled);
方案2:手动拆分段落(轻量适配)
如果文本内容结构固定,可以预先计算大字号文本的宽度,在合适的位置手动插入换行符\n拆分多个独立段落,系统会自动为每个段落单独计算适配自身的行高,和最初手动加\n的效果完全一致。
可选优化配置
给TextView添加以下属性可以提升断行和行高适配效果:
<TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:breakStrategy="high_quality" android:hyphenationFrequency="none" />
内容的提问来源于stack exchange,提问作者Cyprian Gracz
相关产品推荐
相关产品推荐

