react-native icon indicating copy to clipboard operation
react-native copied to clipboard

Lines getting cut-off on Android devices with small font sizes

Open LA-Johan opened this issue 7 months ago • 11 comments

Description

When device font size is set to small words in certain configuration of parent views get cut-off (see reproducer). Our users just started reporting in the last month it so I believe it was introduced in 0.79.

Steps to reproduce

UI bug, see attached screenshots.

React Native Version

0.79.1

Affected Platforms

Runtime - Android, Build - MacOS

Output of npx @react-native-community/cli info

$npx @react-native-community/cli info
info Fetching system and libraries information...
System:
  OS: macOS 15.3.2
  CPU: (12) arm64 Apple M3 Pro
  Memory: 112.06 MB / 36.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 23.7.0
    path: /opt/homebrew/bin/node
  Yarn:
    version: 1.22.22
    path: /opt/homebrew/bin/yarn
  npm:
    version: 11.2.0
    path: ~/node_modules/.bin/npm
  Watchman:
    version: 2025.02.17.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.14.3
    path: /Users/johanlndll/.gem/ruby/3.1.4/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.0
      - iOS 18.0
      - macOS 15.0
      - tvOS 18.0
      - visionOS 2.0
      - watchOS 11.0
  Android SDK:
    API Levels:
      - "30"
      - "34"
      - "35"
    Build Tools:
      - 30.0.3
      - 33.0.0
      - 33.0.1
      - 34.0.0
      - 35.0.0
    System Images:
      - android-30 | Google Play ARM 64 v8a
      - android-34 | Google APIs ARM 64 v8a
      - android-35 | Google APIs ARM 64 v8a
      - android-35 | Google Play ARM 64 v8a
    Android NDK: Not Found
IDEs:
  Android Studio: 2024.2 AI-242.21829.142.2421.12409432
  Xcode:
    version: 16.0/16A242d
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.10
    path: /usr/bin/javac
  Ruby:
    version: 3.1.4
    path: /Users/johanlndll/.rubies/ruby-3.1.4/bin/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 19.1.0
    wanted: 19.1.0
  react-native: Not Found
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: Not found
  newArchEnabled: Not found
iOS:
  hermesEnabled: Not found
  newArchEnabled: Not found

Stacktrace or Logs

UI bug.

MANDATORY Reproducer

https://github.com/facebook/react-native/pull/50915

Screenshots and Videos

Emulator is Pixel_9_API_35

With the issue:

Image Image

Without the issue:

Image Image

LA-Johan avatar Apr 24 '25 21:04 LA-Johan

[!WARNING] Missing reproducer: We could not detect a reproducible example in your issue report. Reproducers are mandatory and we can accept only one of those as a valid reproducer:


You can read more about about it on our website: How to report a bug.

react-native-bot avatar Apr 24 '25 21:04 react-native-bot

Linked it in original, but in case it helps the bot this is pull request: https://github.com/facebook/react-native/pull/50915

LA-Johan avatar Apr 24 '25 21:04 LA-Johan

@LA-Johan Thanks for opening the issue! While reviewing the output of npx @react-native-community/cli info, we couldn’t determine if the new architecture is enabled, could you let us know whether the problem occurs on both the old architecture and the new architecture? This will help us narrow things down. Thanks!

devanshsaini11 avatar Apr 27 '25 10:04 devanshsaini11

@devanshsaini11 this is only on new architecture!

LA-Johan avatar Apr 27 '25 23:04 LA-Johan

If anyone has found a workaround that would be great too. This breaks some of our core flows for users with different font sizes making some text completely unreadable.

LA-Johan avatar Apr 29 '25 16:04 LA-Johan

@devanshsaini11 do you know which classes I might investigate on the Android side to potentially fix this? If I find the time I'd be willing to try and fix this but would appreciate some pointers.

LA-Johan avatar May 06 '25 17:05 LA-Johan

According to my understanding looking into TextLayoutManager or CustomLineHeightSpan might help you.

devanshsaini11 avatar May 07 '25 14:05 devanshsaini11

Haven't had time to try and fix yet but can report issue persists on 0.79.2. Would appreciate any help from the team, accessibility is broken for some of our users who use larger font sizes.

LA-Johan avatar May 13 '25 16:05 LA-Johan

@devanshsaini11 I spent some time debugging this and I've narrowed it down to this code here

When we have a small font size, the width will be smaller than the boring.width on a second measure, causing a StaticLayout to be used, with normal font size the width will be a 1 pixel larger, and a BoringLayout is used instead.

-- SMALL FONT SIZE --
05-13 23:18:02.285 16069 16102 D TextLayoutManager: Row cutoff boring.width: 155, unconstrainedWidth: false, width: 1027.5
05-13 23:18:02.286 16069 16102 D TextLayoutManager: Row cutoff boring.width: 155, unconstrainedWidth: false, width: 132.0
05-13 23:18:02.287 16069 16102 D TextLayoutManager: Row cutoff boring.width: 155, unconstrainedWidth: false, width: 133.0

-- NORMAL FONT SIZE --
05-13 23:18:15.135 16166 16204 D TextLayoutManager: Row cutoff boring.width: 179, unconstrainedWidth: false, width: 1027.5
05-13 23:18:15.136 16166 16204 D TextLayoutManager: Row cutoff boring.width: 179, unconstrainedWidth: false, width: 180.0
05-13 23:18:15.137 16166 16204 D TextLayoutManager: Row cutoff boring.width: 179, unconstrainedWidth: false, width: 180.0

I've tried to find the source of the width but I'm getting lost in the bridging code between js and android, any pointers on where to look next?

05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.views.text.TextLayoutManager.logIfRelevant(TextLayoutManager.java:1041)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.views.text.TextLayoutManager.createLayout(TextLayoutManager.java:462)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.views.text.TextLayoutManager.createLayout(TextLayoutManager.java:609)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.views.text.TextLayoutManager.measureText(TextLayoutManager.java:725)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.views.text.ReactTextViewManager.measure(ReactTextViewManager.java:214)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.fabric.mounting.MountingManager.measureMapBuffer(MountingManager.java:415)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.fabric.FabricUIManager.measureMapBuffer(FabricUIManager.java:642)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.jni.NativeRunnable.run(Native Method)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at android.os.Handler.handleCallback(Handler.java:959)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at android.os.Handler.dispatchMessage(Handler.java:100)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.kt:21)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at android.os.Looper.loopOnce(Looper.java:232)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at android.os.Looper.loop(Looper.java:317)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.bridge.queue.MessageQueueThreadImpl$Companion.startNewBackgroundThread$lambda$1(MessageQueueThreadImpl.kt:175)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.bridge.queue.MessageQueueThreadImpl$Companion.$r8$lambda$ldnZnqelhYFctGaUKkOKYj5rxo4(Unknown Source:0)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at com.facebook.react.bridge.queue.MessageQueueThreadImpl$Companion$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
05-14 08:55:53.810 20205 20241 D TextLayoutManager: 	at java.lang.Thread.run(Thread.java:1012)

Also, I haven't had any luck attaching a debugger to the Android code, any guides I find seem to be for generic react-native project, is there something different I need to do to debug here?

LA-Johan avatar May 14 '25 08:05 LA-Johan

Confirmed this was fixed with the new logic for rounding in https://github.com/facebook/react-native/commit/1fe3ff86c364fad023ad1e426f26608699314339

Note that the previous incorrect logic goes back all the way to legacy arch (ReactTextShadowNode), so I don't think the underlying bug is new, but it relies on getting "unlucky" with pixel grid rounding, so there are different cosmic butterflies that can influence this.

Before After
Image Image

NickGerleman avatar May 30 '25 00:05 NickGerleman

Actually it looks like this can still happen non-deterministically. I will see if I can take a closer look. Though there is a new text stack coming for Android meant to eliminate the source of some of these issues.

NickGerleman avatar May 30 '25 00:05 NickGerleman

@NickGerleman thank you for looking into this. I know you said it doesn't fix the entire issue, but which version of RN will https://github.com/facebook/react-native/commit/1fe3ff86c364fad023ad1e426f26608699314339 go live in?

LA-Johan avatar May 30 '25 13:05 LA-Johan

This issue dates back to 2017, and you could try this workaround: https://github.com/facebook/react-native/issues/15114#issuecomment-2422537975

klxiaoniu avatar Jul 21 '25 07:07 klxiaoniu

Our app started experiencing this issue after upgrading from version 0.72 to 0.77 and enabling the new architecture. We've already received multiple user reports. They all encountered the problem after adjusting the system font size or enabling bold text. This issue did not occur in the previous version.

huanguolin avatar Jul 29 '25 01:07 huanguolin

请问这个问题解决了吗

WenBin0201 avatar Aug 04 '25 12:08 WenBin0201

Just checking in — has anyone figured out a good way to handle this?

WenBin0201 avatar Aug 06 '25 11:08 WenBin0201

Looking at the commits I think some fixes for this are going live with 0.81.0, is that fair to say @NickGerleman ?

LA-Johan avatar Aug 06 '25 15:08 LA-Johan

https://github.com/user-attachments/assets/8003ccfb-e9db-4520-9bd3-fffba367e342

I just initialized a new React Native project with version 0.81.0-rc.3, and simulated the issue by increasing the system font size and weight on the device.

After changing the font size and weight, I observed that some text (usually the last character) gets truncated or disappears, which is consistent with what my users (on Xiaomi and OPPO devices) are experiencing.

Unfortunately, since this mainly happens on end users' devices, I can only provide screenshots, not a full reproduction. @NickGerleman @LA-Johan

WenBin0201 avatar Aug 07 '25 01:08 WenBin0201

@WenBin0201 thank you for checking. I hope words at least stop disappearing completely, bummer it's not fully resolved yet.

LA-Johan avatar Aug 07 '25 15:08 LA-Johan

my workaround:

import { Platform, StyleSheet, Text } from 'react-native';

if (Platform.OS === 'android') {
    const styles = StyleSheet.create({
        defaultText: {
            fontFamily: '',
            // workaround
            fontWeight: 'normal',
        },
    });
    const oldRender = (Text as any).render;
    (Text as any).render = function (props: any, ...args: any[]) {
        return oldRender.call(
            this,
            {
                ...props,
                style: [styles.defaultText, props.style],
            },
            ...args,
        );
    };
}

huanguolin avatar Aug 08 '25 03:08 huanguolin

@huanguolin 这样的话 字重就没了 我现在是设置了 robot字体 并且禁止缩放

WenBin0201 avatar Aug 08 '25 03:08 WenBin0201

@huanguolin 这样的话 字重就没了 我现在是设置了 robot字体 并且禁止缩放

In my case, the fontWeight setting in the code is fine. However, when I set zoom to be disabled, it doesn’t work in version 0.77 (it works in 0.80). Moreover, my users won’t accept this.

huanguolin avatar Aug 09 '25 03:08 huanguolin

Add a scenario: This problem can also occur on some tablet devices with very good screen resolution, such as screens with a resolution of 3200 * 2136 and 308PPI

NiuGuohui avatar Aug 09 '25 15:08 NiuGuohui

mmm seems to occur when some specific length occurs, depending on font props, adding eg style Platform.OS === 'android' && { paddingHorizontal/paddingRight: 0.001 }, helps for, at least one of our cases, but if it helps for all 🤷

OskarAtJoint avatar Aug 13 '25 09:08 OskarAtJoint

@OskarAtJoint I also apply this trick as a backup solution.

WenBin0201 avatar Aug 13 '25 09:08 WenBin0201

Confirmed this was fixed with the new logic for rounding in 1fe3ff8

Note that the previous incorrect logic goes back all the way to legacy arch (ReactTextShadowNode), so I don't think the underlying bug is new, but it relies on getting "unlucky" with pixel grid rounding, so there are different cosmic butterflies that can influence this.

Before After Image Image

Could you please cherry pick this to 0.79?

klxiaoniu avatar Aug 20 '25 01:08 klxiaoniu

https://github.com/user-attachments/assets/7647ed8a-26c5-47c2-8e7d-47da965e347f 这RN的新架构 兼容性太差了

WenBin0201 avatar Sep 24 '25 06:09 WenBin0201

不仅切字 窗口的宽高还计算不准确

WenBin0201 avatar Sep 24 '25 06:09 WenBin0201