Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On Android, TextInputs within a position: absolute view that's inside another view with onLayout can't be focused #29308

Closed
hsource opened this issue Jul 8, 2020 · 11 comments · Fixed by facebook/react-native-website#2537
Labels
Component: TextInput Related to the TextInput component. Component: View Platform: Android Android applications. Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@hsource
Copy link
Contributor

hsource commented Jul 8, 2020

Please provide all the information requested. Issues that do not follow this format are likely to stall.

Description

Given a hierarchy of views:

  1. <View> with onLayout prop
  2. <View> that has position: 'absolute' style
  3. A TextInput

Text inside the TextInput can't be selected. Removing the first view's onLayout prop or the second view's position: 'absolute' will allow text in the TextInput to be selected.

React Native version:

v0.62.2

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

  1. Render inside a component the following:
import * as React from 'react';
import { TextInput, View, Text } from 'react-native';

export default function App() {
  return (
    <View style={{ flex: 1 }}>
      {
        // Remove the onLayout for the text to become selectable
      }
      <View onLayout={() => {}}>
        <View
          style={{
            position: 'absolute',
            width: '100%',
            top: 50,
            paddingHorizontal: 8,
          }}
        >
          <Text style={{ marginBottom: 10 }} wrap>
            The following text should be selectable. For some reason, it's not
            selectable on Android when placed inside the original
            KeyboardAvoidingView or any View with an onLayout callback.
          </Text>
          <TextInput defaultValue="Try selecting this text" />
        </View>
      </View>
    </View>
  );
}
  1. On Android, try to select text inside the TextInput

Expected Results

Describe what you expected to happen.

The text should be selected

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

https://snack.expo.io/@harrytravelchime/react-native-issue-29308

@react-native-bot react-native-bot added Component: TextInput Related to the TextInput component. Platform: Android Android applications. labels Jul 8, 2020
@Shuo-Mr
Copy link

Shuo-Mr commented Sep 4, 2020

I also encountered a similar problem. When the view is absolutely positioned, internal events cannot be triggered, but positioning can be triggered to cover subsequent events, such as Scrollview's scroll event. I think it may be due to hierarchy, but I can't make a mask like thing on the outer layer of the positioned view, because it will affect the layout of peers. I hope someone can help me.

So your problem here, I think, is due to the absolute positioning.

@farshed
Copy link

farshed commented Sep 5, 2020

Touchables inside absolutely positioned View not working either

@safaiyeh
Copy link
Contributor

safaiyeh commented Sep 6, 2020

Interesting bug, I was able to see this in the snack. I've seen some PRs and issues relating to hierarchy of view elements. I wonder if one of those would help (don't have a list of them handy on me right now)

@anhquan291
Copy link

Same problem here. It works just fine on iOS but Android.

@fabOnReact
Copy link
Contributor

from quick troubleshooting I notice that onTouchEvent is not triggered when we use absolute position

I troubleshooted something similar #27333 (comment) and #27333 (comment) but in this case I think this is an actual bug.

Also many information about this issue are included in #29911 #25441 #28694

Most of the time this can be fixed using react-native-gesture-handler component, but in this case it is not possible. I further investigate.

@ella33
Copy link

ella33 commented Mar 5, 2021

Same problem here. TextInput does not get focused and the buttons aren't pressable on Android if it's inside an absolutely positioned View and it happens even without onLayout. Eg.

  <View style={{ position: 'absolute', bottom: 0, paddingVertical: 10, paddingHorizontal: 15 }}>
      <Pressable onPress={() => {}}>
        <PlusIcon />
      </Pressable>

      <TextInput ref={inputRef} style={styles.newMessageInput} multiline={true} onChangeText={onMessageChange} />

      <Pressable onPress={sendMessage}>
        <SendIcon />
      </Pressable>
    </View>

@fabOnReact
Copy link
Contributor

fabOnReact commented Mar 8, 2021

https://reactnative.dev/docs/touchablewithoutfeedback#hitslop

The touch area never extends past the parent view bounds.

The parent is absolute positioned and has computed height of 0, does not allow you to click/press on the childs.
I fixed the example by giving height parent > height of child, click the links below for a more detailed explanation:

CLICK TO OPEN - CODE SNIPPET

class RewriteExampleInvalidCharacters extends React.Component {
  render() {
    return (
      <View
        nativeID="1"
        style={{backgroundColor: 'yellow', height: 150}}
        onLayout={() => {}}>
        <View
          nativeID="2"
          style={{
            position: 'absolute',
            top: 0,
            bottom: 0,
            left: 0,
            right: 0,
            zIndex: 2,
            height: 100,
            backgroundColor: 'red',
          }}>
          <TextInput nativeID="3" defaultValue="Try selecting this text" />
        </View>
      </View>
    );
  }
}

CLICK TO OPEN - REACTANDROID JAVA METHOD ANALYSIS

In the example included in this issue child.getBottom() and child.getTop() are equal, because the element with absolute positioning (nativeID="1" in my example) has height = 0 and the method returns false.

&& (localY >= 0 && localY < (child.getBottom() - child.getTop()))) {
outLocalPoint.set(localX, localY);
return true;

CLICK TO OPEN TESTS RESULTS - VIDEO CLICKING ON TEXTINPUT

height of parent > height of child - TextInput text is selectable
2021-03-08.16-11-30.mp4

CLICK TO OPEN - VIDEO EXPLANATION OF THE REASON

In the example below the child.getBottom and child.getTop are equal, meaning the height of container is 0.
The view with nativeID="1" has height = 0, in java getTop returns 330 and getBottom returns 330 for this native view. The method below returns false and his childs are not touchable

&& (localY >= 0 && localY < (child.getBottom() - child.getTop()))) {
outLocalPoint.set(localX, localY);
return true;

      <View
        nativeID="1"
        style={{backgroundColor: 'yellow'}}
        onLayout={() => {}}>
        <View
          nativeID="2"
          style={{
            position: 'absolute',
            top: 0,
            bottom: 0,
            left: 0,
            right: 0,
            zIndex: 2,
            // height: 100,
            backgroundColor: 'red',
          }}>
          <TextInput nativeID="3" defaultValue="Try selecting this text" />
        </View>
      </View>
parent height is 0
2021-03-08.16-44-08.mp4

In the example below the child.getBottom and child.getTop are not equal, meaning the height of container is > 0.
The view with nativeID="1" has height = 150, in java getTop returns 330 and getBottom returns 780 for this native view. The method below returns true and his childs are touchable

&& (localY >= 0 && localY < (child.getBottom() - child.getTop()))) {
outLocalPoint.set(localX, localY);
return true;

      <View
        nativeID="1"
        style={{backgroundColor: 'yellow', height: 150}}
        onLayout={() => {}}>
        <View
          nativeID="2"
          style={{
            position: 'absolute',
            top: 0,
            bottom: 0,
            left: 0,
            right: 0,
            zIndex: 2,
            // height: 100,
            backgroundColor: 'red',
          }}>
          <TextInput nativeID="3" defaultValue="Try selecting this text" />
        </View>
      </View>
parent View height > 0
2021-03-08.16-44-44.mp4

Related #25441 #28694 #27333 (comment)

@RigottiG
Copy link

RigottiG commented Sep 2, 2021

I'm facing the same issue here

@stale
Copy link

stale bot commented Jan 9, 2022

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jan 9, 2022
@PaoloGuimalan
Copy link

Hey guys I've fixed mine and this might fix yours! The thing that is happening when you position a view as absolute, the view automatically being placed at the bottom of Z index placement. So basically react native uses the html concepts about z Index. We cannot focus the textinputs and touchables within the absolute view because when we click it we are clicking the View which positioned in the same place the absolute view is at. So we need to elevate the absolute view by putting "zIndex: 1" or "zIndex: 1000", depending on how many elements your absolute view overlapped. So basically this not a bug, it's just a plain old html concept we missed.

@hsource
Copy link
Contributor Author

hsource commented May 1, 2023

The root cause of this issue is #37181

I included some workarounds in that issue too

@hsource hsource closed this as completed May 1, 2023
@hsource hsource closed this as not planned Won't fix, can't repro, duplicate, stale May 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: TextInput Related to the TextInput component. Component: View Platform: Android Android applications. Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
10 participants