Mobile Development 24 min read

Why Text Gets Cut Off in React Native – Android Measurement Deep Dive & Fixes

This article analyzes the long‑standing React Native text‑truncation issue, explains Android’s text‑measurement architecture—including Spanned, TextPaint, Layout and TextLine—examines two common truncation cases, provides concrete fixes, and proposes a runtime monitoring solution to detect and log such problems.

Kuaishou Frontend Engineering
Kuaishou Frontend Engineering
Kuaishou Frontend Engineering
Why Text Gets Cut Off in React Native – Android Measurement Deep Dive & Fixes

Background

React Native has long suffered from text truncation (also called “phone swallowing characters”) where strings are cut off on certain Android devices.

Text Measurement Principles

Text measurement in Android is performed by a set of core classes: Spanned , TextPaint , Layout and TextLine . Spanned abstracts span data, TextPaint holds paint properties, Layout defines the measurement and drawing process, and TextLine handles per‑line layout.

Key interfaces include CharacterStyle , ParagraphStyle , MetricAffectingSpan , UpdateAppearance , UpdateLayout , etc.

FontMetrics defines the geometric properties of a font.

<code>public static class FontMetrics {
    public float top;
    public float ascent;
    public float descent;
    public float bottom;
    public float leading;
}</code>

Analysis of Truncation Cases

1. fontFamily = null

When the Text component does not specify a fontFamily , React Native creates a CustomStyleSpan with a null typeface. During the YogaMeasure phase the TextPaint has no typeface, producing a narrower width. In the onMeasure phase the TextView applies the system default typeface, resulting in a larger width. The mismatch makes BoringLayout width exceed the wanted width, causing StaticLayout to wrap and truncate the end of the line.

2. System font scaling

Changing the system font scale on MIUI 12/13/14 alters the underlying Misans font metrics, making the width measured in Yoga different from the width measured later, again leading to BoringLayout width > wantWidth and truncation.

Solutions

Ensure the same TextPaint configuration in both phases. For case 1, force the default typeface in YogaMeasure (e.g., reuse TextView#setTypefaceFromAttrs ). For case 2, apply the same font size in onBeforeLayout as in onMeasure , typically via ReactAbsoluteSizeSpan .

A PR has been merged into React Native to address the issue:

Monitoring Scheme

Detect truncation at runtime by comparing the width and line count of the Layout used by Yoga with the Layout after onMeasure :

TextView.mBoring.width > Yoga.mBoring.width

TextView.mLayout.getLineCount() > Yoga.mLayout.getLineCount()

When both conditions hold, log a truncation event.

Conclusion

The article provides a comprehensive overview of Android text measurement, identifies root causes of React Native text truncation, offers concrete fixes, and proposes a lightweight monitoring solution to detect and log such problems.

performancelayoutAndroidReact NativeText TruncationText Measurement
Kuaishou Frontend Engineering
Written by

Kuaishou Frontend Engineering

Explore the cutting‑edge tech behind Kuaishou's front‑end ecosystem

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.