react-native: Problem with TextInput lineHeight on iOS

Hi, guys! Did someone facing the same issue with lineHeight on iOS ? any solution ?

React Native version: “0.61.5”

Android: Screenshot 2020-02-10 at 16 21 04

iOS: Screenshot 2020-02-10 at 16 21 13

Screenshot 2020-06-03 at 20 23 56

Code:

import React from 'react'
import { View, TextInput, StyleSheet } from 'react-native'

export default function Example () {
  return (
    <View style={styles.wrapper}>
      <TextInput style={styles.input} placeholder='Hello World!' />
    </View>
  )
}

const styles = StyleSheet.create({
  wrapper: {
    height: '100%',
    width: '100%',
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'lightgray'
  },
  input: {
    height: 32,
    minWidth: 120,
    lineHeight: 32,
    borderWidth: 1,
    backgroundColor: 'white',
    padding: 0,
    fontSize: 14
  }
})

same on 0.62.2 version

rn info:

System:
    OS: macOS 10.15.5
    CPU: (8) x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
    Memory: 404.19 MB / 16.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 14.2.0 - ~/.nvm/versions/node/v14.2.0/bin/node
    Yarn: 1.17.3 - /usr/local/bin/yarn
    npm: 6.14.4 - ~/.nvm/versions/node/v14.2.0/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.1 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 13.5, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
    Android SDK: Not Found
  IDEs:
    Android Studio: 3.6 AI-192.7142.36.36.6241897
    Xcode: 11.5/11E608c - /usr/bin/xcodebuild
  Languages:
    Java: 13.0.2 - /usr/bin/javac
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: ^16.13.1 => 16.13.1
    react-native: 0.62.2 => 0.62.2
  npmGlobalPackages:
    *react-native*: Not Found

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 19
  • Comments: 20 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Is there a workaround for this? still happening in RN v0.72.3

Example from Issue https://github.com/facebook/react-native/issues/28012

Text is not correctly aligned when using lineHeight and height in a TextInput.

Before applying the fix

<video src="https://user-images.githubusercontent.com/24992535/235421165-e1553caf-ef32-4223-8ffb-13aee320953f.mp4" width="200" />

After applying the fix

<video src="https://user-images.githubusercontent.com/24992535/235421377-23bbee11-adde-40de-9ded-a293f4010bbb.mp4 " width="200" />

https://user-images.githubusercontent.com/24992535/235421238-302c1cd6-806a-491d-9321-eeb03815a9b5.mp4

For the past few years I’ve just avoided using lineHeight on React Native, as it’s more trouble than it’s worth. However, while you can add padding to a single line there’s no decent hack for multiline text. Hopefully there’s a solution soon.

@askel4dd That doesn’t seem to fix the issue.

It seems that the problem only happens on iOS with large fontSize-lineHeight differences. (In the original example fontSize: 14 and lineHeight: 32.) The workaround for me right now is to set lineHeight: null and use a wrapper View to achieve correct positioning.

Please re-state the problem that we are trying to solve in this issue.

What is the root cause of that problem?

The issue is caused by adding lineHeight to TextInput (Issue https://github.com/facebook/react-native/issues/28012).

What changes do you think we should make in order to solve the problem?

Fix react-native TextInput (iOS) font metrics (descent) to avoid cutting text when setting the lineHeight ( https://stackoverflow.com/a/27631737/7295772).

  1. react-native TextInput is just a wrapper around the iOS API UITextField
  2. the TextInput text is styled with NSAttributedString

The issue only reproduces with TextInput, but not with Text, while both manage text style using the same API RCTAttributedTextUtils.

The text is cut when setting the lineHeight prop. The TextInput component sets the lineHeight without adjusting the baseline of the text with RCTBaselineOffset (RCTAttributedTextUtils#RCTNSTextAttributesFromTextAttributes). Text and TextInput component use shared API AttributedText to style the Text in the TextInput, but TextInput currently misses this logic (RCTApplyBaselineOffset). It was tested with this video (https://github.com/Expensify/App/issues/17767#issuecomment-1526631224) in the Expensify App. Changing RCTApplyBaselineOffset does not change the baseline of the AttributedText in the TextInput, but changes the baseline of the appended Text.

As we can see the Text is cut if lineHeight is lower then Text height (image)

Commenting the code and the Text is not cut (image)

It is caused by the missing implementation in the TextInput of RCTBaselineOffset, which correctly sets the Text baseline and avoids cutting the text

RCTTextInputComponentView generates the text with RCTNSTextAttributesFromTextAttributes instead of RCTNSAttributedStringFromAttributedString

RCTBaselineOffset changes the text baseline (see the above screenshots and https://github.com/Expensify/App/issues/17767#issuecomment-1526631224) and avoids this regression with Text component, but it is not implemented for TextInput component.

Summary:

  • The string is not cut while using Text component.
  • Text and TextInput components use the same API to style the text (AttributedString).
  • The Text component applies custom logic when applying setting the lineHeight (RCTBaselineOffset). The logic modifies the text fontMetrics and avoids cutting the text.
  • There is a missing implementation of RCTBaselineOffset in TextInput, which causes the regression (the text has the wrong baseline and it is cut).