Commit 6306468
Fix adjustsFontSizeToFit clipping when container height shrinks on Android (#57597)
Summary:
When a `<Text adjustsFontSizeToFit>` component's container height decreases dynamically (e.g. height=60 → height=20), the text is clipped instead of having its font size recalculated.
**Root cause:** `mShouldAdjustSpannableFontSize` — the gate that triggers font recalculation in `onDraw` — is only set by text-content setters (`setSpanned`, `setNumberOfLines`, etc.). A pure container resize never sets it. Meanwhile the background Fabric measurement thread mutates the shared cached spannable (`tagToSpannableCache`) to the larger font size. When the container then shrinks, `onDraw` skips recalculation and draws the stale large font in the smaller container, causing clipping.
**Fix:** Override `onSizeChanged` in `ReactTextView` to set `mShouldAdjustSpannableFontSize = true` whenever the view dimensions change and `adjustsFontSizeToFit` is active. Android automatically schedules a redraw on size change, so the next `onDraw` recalculates the font with the correct current height.
**Note on the shared spannable:** the recalculation in `onDraw` mutates the (possibly shared) cached spannable on the UI thread via `adjustSpannableFontToFit` followed by `setText`. This change makes that recalculation also run on a container resize, so it rides the existing UI-thread mutation of the shared spannable a bit more often. It is the same mutation already performed on content changes, so it does not introduce a new race, but it is worth flagging if the spannable caching is revisited.
## Changelog:
[ANDROID] [FIXED] - Fix Text with adjustsFontSizeToFit being clipped when container height decreases dynamically
Pull Request resolved: #57597
Test Plan:
Tested using the existing RNTester example which already reproduces this bug:
1. Build and run RNTester on Android
2. Navigate to **Text** → **Font Size Adjustment with Dynamic Layout**
3. Press **Set Height to 60** — text grows to fill the yellow container
4. Press **Set Height to 20** — before this fix, text is clipped; after this fix, text shrinks to fit correctly
5. Repeat steps 3–4 rapidly — no clipping at any point
The reproducer is `packages/rn-tester/js/examples/Text/TextAdjustsDynamicLayoutExample.js`.
Automated: added `ReactTextViewTest.adjustsFontSizeToFitRecalculatesWhenContainerHeightShrinks`, which lays out an `adjustsFontSizeToFit` text at a tall height then a short height and asserts the `ReactAbsoluteSizeSpan` font size shrinks. It fails without this change (the resize does not retrigger recalculation) and passes with it.
NOTE: Addition video provided by the author in the PR.
Reviewed By: cortinico
Differential Revision: D112811263
Pulled By: fabriziocucci
fbshipit-source-id: 411f61c9f678a3fc36a073300ce3cb57b56e2be61 parent 3861118 commit 6306468
3 files changed
Lines changed: 62 additions & 0 deletions
File tree
- packages/react-native/ReactAndroid
- api
- src
- main/java/com/facebook/react/views/text
- test/java/com/facebook/react/views/text
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6029 | 6029 | | |
6030 | 6030 | | |
6031 | 6031 | | |
| 6032 | + | |
6032 | 6033 | | |
6033 | 6034 | | |
6034 | 6035 | | |
| |||
Lines changed: 8 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
313 | 313 | | |
314 | 314 | | |
315 | 315 | | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
316 | 324 | | |
317 | 325 | | |
318 | 326 | | |
| |||
Lines changed: 53 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
22 | 23 | | |
| 24 | + | |
23 | 25 | | |
24 | 26 | | |
25 | 27 | | |
| |||
45 | 47 | | |
46 | 48 | | |
47 | 49 | | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
48 | 101 | | |
49 | 102 | | |
50 | 103 | | |
| |||
0 commit comments