react-native: [Android] textAlignVertical doesn't work on nested text

This issue has already been reported (#18790), but closed for “stalling”. As of React Native 0.63.3, the bug still exists.

Description

textAlignVertical works fine when set on the top-most Text component. However, if you have any nested texts (a common use case), you can not override the alignVertical in the child Text component.

React Native version:

System: OS: Linux 5.4 Manjaro Linux CPU: (8) x64 Intel® Core™ i7-8809G CPU @ 3.10GHz Memory: 1.54 GB / 31.29 GB Shell: 5.8 - /bin/zsh Binaries: Node: 14.15.0 - /tmp/xfs-2fbb69bb/node Yarn: 2.2.2 - /tmp/xfs-2fbb69bb/yarn npm: 6.14.8 - /usr/bin/npm Watchman: 4.9.0 - /usr/bin/watchman SDKs: Android SDK: API Levels: 28, 29 Build Tools: 28.0.3, 29.0.0, 29.0.2, 29.0.3, 30.0.0, 30.0.1 System Images: android-22 | Google APIs Intel x86 Atom, android-23 | Google APIs Intel x86 Atom, android-29 | Google APIs Intel x86 Atom, android-30 | Google Play Intel x86 Atom Android NDK: Not Found IDEs: Android Studio: 4.1 AI-201.8743.12.41.6858069 Languages: Java: 1.8.0_265 - /usr/bin/javac Python: 3.8.6 - /usr/bin/python npmPackages: @react-native-community/cli: Not Found react: 16.13.1 => 16.13.1 react-native: ^0.63.3 => 0.63.3 npmGlobalPackages: react-native: Not Found

Steps To Reproduce

Create an app which renders the following component:

export default function App() {
  return (
      <Text>
        <Text>This is text</Text>
        <Text style={{textAlignVertical: 'top', fontSize: 10}}>sup!</Text>
      </Text>
  );
}

Expected Results

The “sup!” Text node should be aligned to the top edge of the line. Instead, “sup!” is aligned with the baseline:

Web (expected)

2020-11-12-141856_128x45_scrot

Android

2020-11-12-141936_167x69_scrot

Snack, code example, screenshot, or link to a repository:

https://snack.expo.io/@jsamr/android-textalignvertical

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 18
  • Comments: 25 (16 by maintainers)

Commits related to this issue

Most upvoted comments

@fabriziobertoglio1987 Awesome! Thanks for your research. Looking forwards to your PR 🙂

@fabriziobertoglio1987 That is promising! Although it would be more like super / sub support rather than a fix for this peculiar issue. But a very exciting new feature! Below just a recap on the distinction between super and top.

In CSS, top, bottom are quite different than sub and sup:

The baseline-relative values %, sub, super shift the box relative to its baseline-aligned position, whereas the line-relative values top, center, and bottom shift the inline box and its contents relative to the bounds of its line box.

What that basically mean is that, if you have a sibling which expands the line box such as a big image, top would put the content aligned with the top of the image (which coincide with the line box) while super would only shift the content a little bit up from the baseline.

See this JSFiddle

But honestly, I have no idea what are the specs of React Native inline layout! There certainly are models for native platforms.

Hello,

Thanks for the issue. I have been contributing to facebook/react-native for 4 years and specialize in the Text/TextInput components. I currently have 58 facebook/react-native PRs:

https://github.com/facebook/react-native/pulls?q=is%3Apr+author%3Afabriziobertoglio1987+

This is the suggested approach from the react-native core team (see this discussion):

I’m publishing several fixes for Text and TextInput component in a separate library react-native-improved.

  • The Component is based on ReactTextView, it is the same implementation from react-native.
  • It will include several bug fixes.
  • You can use the library until the PR is merged and released with react-native.
  • You can use side by side both components from react-native and react-native-improved, depending on where you need the fix.
  • I will also publish the PR to facebook/react-native (daily fixes and releases).

The advantages would be:

  • Increased engagement with the community, issues are quickly fixed.
  • No limitations when merging PRs (react-native main branch is used on facebook marketplace).
  • Only Meta employees can merge and review facebook/react-native PRs.
  • Allows us to further experiment and develop react-native.

What do you think about this? Should I keep working on this? Thanks

Still an issue

I was able to prepare a fix for this issue, the problem is that I don’t know how to pass the prop. The prop textAlignVertical: 'super' needs to be passed to the span (the nested/child <Text>sup!</Text>) and not the parent android TextView (the parent react <Text>This is text</Text>).

The class that handle TextView attributes is ReactTextAnchorViewManager which for example applies the prop TEXT_ALIGN_VERTICAL and changes the alignment of the parent Text.

https://github.com/facebook/react-native/blob/cf0a6e9e2734a5927b9dc08303c22477ad274150/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java#L72

while the second child/nexted text <Text>This is text<Text>sup!</Text></Text> is just part of the original TextView, but it is styled differently using an android SuperscriptSpan insted of for example CustomLetterSpacingSpan

https://github.com/facebook/react-native/blob/cf0a6e9e2734a5927b9dc08303c22477ad274150/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L176-L180

This properties are applied by the ReactBaseTextShadowNode and are taked from the textAttributes properties listed below

https://github.com/facebook/react-native/blob/cf0a6e9e2734a5927b9dc08303c22477ad274150/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L323-L330

I still did not find the logic that adds this properties to the ReactBaseTextShadowNode, but I imagine may be in the ReactTextViewAnchorManager

I will have to further investigate were to add this property, probably I will have to investigate how the style properties are used to add the spans. Thanks a lot for the patience in adding this feature 🙏

@jsamr thanks a lot Jules Randolph for the sponsorship. I will give priority to this issue and publish a pull request. 🙏 ☮️ ❤️

each one of the below code-snippets adds a different text property to the Text sup! using the Android Spans API. Hopefully I will be able to use AlignmentSpan to add the required functionality…

<image src="https://user-images.githubusercontent.com/24992535/108502357-f845c800-72b2-11eb-9b88-2f82226540a5.png" height="50" />
CLICK TO OPEN CODE SNIPPETS

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L174

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L178-L179

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L186

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L193

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L199-L207

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L210

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L213

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L220-L227

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L233

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L235

unluckily @hoda-oz is right

Even if Text components are nested in other Text components, they are merged into a single TextView of Android So you cannot manipulate text position in nested Text components. In this case, you can manipulate vertical position by lineHeight property.

I have been reading https://github.com/facebook/react-native/pull/23195/files and https://github.com/facebook/react-native/pull/8619/files to understand how nested Text are combined in one TextView

<Text>
  <Text>This is text</Text>
  <Text style={{textAlignVertical: 'top', fontSize: 10, backgroundColor: "red" }}>sup!</Text>
</Text>
<image src="https://user-images.githubusercontent.com/24992535/108385384-e6f5b080-720b-11eb-8e4e-513a3446a9aa.png" width="1000" />

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L42-L47

The code below loops the different text and probably is responsible for aggregating them in 1 TextView.

<image src="https://user-images.githubusercontent.com/24992535/108392715-45725d00-7213-11eb-9cab-d8b5e3cc5f7d.png" height="50" />

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L111-L112

each one of the below code-snippets adds a different text property to the Text sup! using the Android Spans API. Hopefully I will be able to use AlignmentSpan to add the required functionality…

<image src="https://user-images.githubusercontent.com/24992535/108502357-f845c800-72b2-11eb-9b88-2f82226540a5.png" height="50" />
More code references

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L174

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L178-L179

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L186

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L193

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L199-L207

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L210

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L213

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L220-L227

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L233

https://github.com/facebook/react-native/blob/28fb41a0ab48cc01d606b64744c84e2ac3805f3f/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java#L235