Commit 9bcb81f
committed
fix(ios): center TextInput text, placeholder, and caret when lineHeight > fontSize
On iOS, when a `TextInput` has `lineHeight > fontSize`, UIKit misrenders three
surfaces:
1. Typed text — glyphs anchor to the bottom of the attributed-string line box
instead of centering within it.
2. Placeholder — inherits the paragraph style from `defaultTextAttributes` and
sits low.
3. Single-line caret — sized to the full paragraph line-box height rather than
the font height, visibly taller than the glyph.
The fix splits two ways depending on which UIKit draw path is involved:
- UITextView (multi-line) and the UILabel-based placeholder paths honor
`NSBaselineOffsetAttributeName`. Computing
`(maxLineHeight - font.lineHeight) / 2` and applying it as a baseline offset
re-centers the glyph in the line box.
- UITextField's UIFieldEditor draw path does not honor
`NSBaselineOffsetAttributeName` for typed text, and the caret rect is sized
from the same paragraph-style line box. For single-line inputs we instead
zero the paragraph-style line height for the value passed to UIKit.
UITextField then renders at the font's natural line height and its built-in
vertical centering positions the glyph in the bounds; the caret rect shrinks
to match. `defaultTextAttributes` keeps the unmodified paragraphStyle so the
placeholder path still sees the real lineHeight, and Yoga's frame-height
measurement is unaffected.
The typed-text fix lives in `RCTTextInputComponentView._setAttributedString:`
so it runs against text round-tripped through UIKit's `typingAttributes` (which
drops `NSParagraphStyleAttributeName`); we re-seed paragraph style from
`defaultTextAttributes` before applying the offset / strip. The placeholder
fixes are local to `_placeholderTextAttributes` in each backing view since both
backing views are shared between Paper and Fabric.
## Changelog
[IOS] [FIXED] - Center typed TextInput text, placeholder, and single-line caret when `lineHeight > fontSize`.
## Test Plan
RN Tester → **TextInput → lineHeight baseline** renders one single-line and
one multi-line `TextInput` with `fontSize: 16, lineHeight: 32`. Before:
placeholder sits low, typed glyphs anchor to the bottom of the line box,
single-line caret overshoots the glyph. After: placeholder and typed text
render vertically centered; single-line caret matches the glyph height.1 parent 46f6d16 commit 9bcb81f
3 files changed
Lines changed: 39 additions & 0 deletions
File tree
- packages/react-native
- Libraries/Text/TextInput
- Multiline
- Singleline
- React/Fabric/Mounting/ComponentViews/TextInput
Lines changed: 7 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
364 | 364 | | |
365 | 365 | | |
366 | 366 | | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
367 | 374 | | |
368 | 375 | | |
369 | 376 | | |
| |||
Lines changed: 7 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
169 | 169 | | |
170 | 170 | | |
171 | 171 | | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
172 | 179 | | |
173 | 180 | | |
174 | 181 | | |
| |||
Lines changed: 25 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
768 | 768 | | |
769 | 769 | | |
770 | 770 | | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
771 | 796 | | |
772 | 797 | | |
773 | 798 | | |
| |||
0 commit comments