TextView Line Spacing Screen Adaptation Solution for Android
To solve Android’s screen‑fragmentation‑induced TextView line‑spacing inconsistencies, Baidu’s team analyzed the default line‑height calculation, then created a custom LineHeightSpan (ExcludeInnerLineSpaceSpan) applied through a subclassed ETextView to enforce visual‑defined line height, delivering a simple, low‑intrusion, cross‑resolution fix.
Android screen fragmentation has become a serious issue, with various screen resolutions emerging constantly. Achieving consistent effects across different resolution screens is a shared goal for Baidu App's R&D and design teams.
In Baidu App's Android development, the TextView line spacing screen adaptation problem has been a long-standing pain point between development and design teams. The same TextView displays different line spacing on devices with different resolutions, which has become a major issue in daily UI development and design review processes, reducing work efficiency.
Analysis:
The article analyzes why TextView exhibits inconsistent line spacing across different devices. Baidu App's UI team uses Sketch tool for UI design and review, so font size measurements in this article are done using Sketch.
When running the same XML layout on devices with different resolutions, the measured line spacing varies: on 720p devices, line spacing measures 5px; on 1080p devices, it measures 9px. Even on the same device (Mate 20), different font sizes produce different line spacing values - the larger the font size, the larger the line spacing.
The root cause is the discrepancy between visual definition of line spacing and Android system's definition. Visually, line spacing is measured as the distance between adjacent text rectangles. However, even without setting lineSpacingExtra or lineSpacingMultiplier properties, there still exists some line spacing from the visual perspective.
Through analysis of TextView source code (StaticLayout.java), the line height calculation formula is: line height = descent - ascent (descent is positive, ascent is negative). Since Chinese characters don't vary in height like English letters, they are uniform block characters. When Chinese characters are drawn within the descent range below the baseline, they don't occupy all the space, leaving some distance. The same applies to the ascent range above the baseline. Therefore, the line spacing measured by Sketch is the remaining space from the previous line's descent range plus the remaining space from the next line's ascent range.
Adaptation Solution:
After analysis, the solution is to remove the default line spacing by modifying TextView's default line height to match the visual definition. TextView provides an interface to modify line height through the LineHeightSpan interface.
The implementation uses a custom ExcludeInnerLineSpaceSpan class that implements LineHeightSpan to remove TextView's built-in line spacing:
public class ExcludeInnerLineSpaceSpan implements LineHeightSpan {
private final int mHeight;
public ExcludeInnerPaddingSpan(int height) {
mHeight = height;
}
@Override
public void chooseHeight(CharSequence text, int start, int end,
int spanstartv, int lineHeight,
Paint.FontMetricsInt fm) {
final int originHeight = fm.descent - fm.ascent;
if (originHeight <= 0) {
return;
}
final float ratio = mHeight * 1.0f / originHeight;
fm.descent = Math.round(fm.descent * ratio);
fm.ascent = fm.descent - mHeight;
}
}Then a custom ETextView is created that provides a setCustomText() method:
public class ETextView extends TextView {
public void setCustomText(CharSequence text) {
if (text == null) {
return;
}
int lineHeight = (int) getTextSize();
SpannableStringBuilder ssb;
if (text instanceof SpannableStringBuilder) {
ssb = (SpannableStringBuilder) text;
ssb.setSpan(new ExcludeInnerLineSpaceSpan(lineHeight),
0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
ssb = new SpannableStringBuilder(text);
ssb.setSpan(new ExcludeInnerLineSpaceSpan(lineHeight),
0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
setText(ssb);
}
}This solution uses system public APIs, is simple, and has low intrusion. It has been deployed on Baidu App's trending page, showing effective adaptation results with before-and-after comparison.
Baidu App Technology
Official Baidu App Tech Account
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.