facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.62k stars 24.29k forks source link

`TextInput` in Android doesn't respect the `selection` attribute and places the caret at the beginning #46943

Open QichenZhu opened 7 hours ago

QichenZhu commented 7 hours ago

Description

Create a TextInput component with value and selection attributes, then programmatically focus it after a delay. You'll find the caret at the beginning instead of at the specified selection.

This is only reproducible under the New Arch.

Steps to reproduce

  1. Clone reproducer or use the code below.
// App.tsx

import { TextInput } from 'react-native';
import { useEffect, useRef} from 'react';

export default function App() {
  const input = useRef(null);
  useEffect(() => { setTimeout(() => input.current?.focus(), 1000); }, []);
  return <TextInput ref={input} value='1.00' selection={{start: 4, end: 4}} />;
}
  1. Build the app with New Arch enabled and run it on Android.

  2. Wait a second.

Expected result: The caret is at the end.

Actual result: The caret is at the beginning.

React Native Version

0.75.4

Affected Platforms

Runtime - Android

Output of npx react-native info

System:
  OS: Linux 5.15 Linux Mint 21.3 (Virginia)
  CPU: (6) x64 AMD Ryzen 5 3500X 6-Core Processor
  Memory: 37.72 GB / 39.16 GB
  Shell:
    version: 5.1.16
    path: /bin/bash
Binaries:
  Node:
    version: 20.15.1
    path: ~/.nvm/versions/node/v20.15.1/bin/node
  Yarn:
    version: 3.6.4
    path: ~/.nvm/versions/node/v20.15.1/bin/yarn
  npm:
    version: 10.7.0
    path: ~/.nvm/versions/node/v20.15.1/bin/npm
  Watchman:
    version: 20231008.002904.0
    path: /usr/local/bin/watchman
SDKs:
  Android SDK:
    API Levels:
      - "31"
      - "33"
      - "34"
    Build Tools:
      - 33.0.1
      - 34.0.0
    System Images:
      - android-34 | Intel x86_64 Atom
      - android-34 | Google APIs Intel x86_64 Atom
    Android NDK: Not Found
IDEs:
  Android Studio: Not Found
Languages:
  Java:
    version: 17.0.12
    path: /usr/bin/javac
  Ruby: Not Found
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.3.1
    wanted: 18.3.1
  react-native:
    installed: 0.75.4
    wanted: 0.75.4
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: Not found
  newArchEnabled: false

Stacktrace or Logs

N/A

Reproducer

https://github.com/QichenZhu/reproducer-react-native-textinput.git

Screenshots and Videos

https://github.com/user-attachments/assets/b0e2f80d-f76d-4c32-b410-3c460aed404b

shubhamguptadream11 commented 4 hours ago

@QichenZhu Is this happening only on Android? Did you get a chance to check on iOS?

QichenZhu commented 3 hours ago

@shubhamguptadream11 It works fine on iOS.

https://github.com/user-attachments/assets/0802560c-ca6f-4057-b5d1-d96ec012c59d

QichenZhu commented 3 hours ago

In my testing, the selection changed after this line.

https://github.com/facebook/react-native/blob/699f73a6b0734fe716b01d263e9579bca38c4652/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java#L1060

A possible fix is to save and restore the selection before and after it.

int prevSelectionStart = getSelectionStart();
int prevSelectionEnd = getSelectionEnd();
super.setTextIsSelectable(true);
setSelection(prevSelectionStart, prevSelectionEnd);

I can create a PR if you're interested.

shubhamguptadream11 commented 2 hours ago

Yeah sure go ahead!