facebook / react-native

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

TextInput prevent scroll on ScrollView #25594

Open Aiiros opened 5 years ago

Aiiros commented 5 years ago

In a too long form, scroll is only available if the touch start outside the TextInput fields

React Native version:

info Fetching system and libraries information...
System:
    OS: Linux 4.15 Ubuntu 18.04.2 LTS (Bionic Beaver)
    CPU: (4) x64 Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz
    Memory: 1.92 GB / 7.67 GB
    Shell: 5.4.2 - /usr/bin/zsh
  Binaries:
    Node: 8.10.0 - /usr/bin/node
    npm: 3.5.2 - /usr/bin/npm
  SDKs:
    Android SDK:
      API Levels: 22, 23, 26, 27, 28
      Build Tools: 23.0.1, 27.0.3, 28.0.3
      System Images: android-27 | Google APIs Intel x86 Atom, android-28 | Google APIs Intel x86 Atom
  npmPackages:
    react: 16.8.6 => 16.8.6 
    react-native: 0.60.0 => 0.60.0 
  npmGlobalPackages:
    react-native-cli: 2.0.1
    react-native-debugger: 1.1.0
    react-native: 0.59.3

Steps To Reproduce

  1. create a ScrollView with flex: 1
  2. put more TextInputs than your screen can handle
  3. try to scroll with your touch starting on a field

Describe what you expected to happen:

I expect the page to scroll

Snack, code example, or link to a repository:

     <ScrollView style={{ flex: 1, }}>
            <TextInput placeholder="test" textAlign='center'/>
            <TextInput placeholder="test" textAlign='center'/>
            <TextInput placeholder="test" textAlign='center'/>
            <TextInput placeholder="test" textAlign='center'/>
            <TextInput placeholder="test" textAlign='center'/>
            <View style={{ height: 150, }} />
            <TextInput placeholder="test" textAlign='center'/>
            <TextInput placeholder="test" textAlign='center'/>
            <TextInput placeholder="test" textAlign='center'/>
            <TextInput placeholder="test" textAlign='center'/>
        </ScrollView>

snack: https://snack.expo.io/@aiiros/react-native-issue-25594

this is a duplicate of https://github.com/facebook/react-native/issues/15962 which has not yet been answered.

Edit: Turns out textAlign='center' is causing all of this

RobinCsl commented 5 years ago

Hi @Aiiros,

I tried to reproduce your issue on Expo Snack: https://snack.expo.io/@robincsl/https:-github.com-facebook-react-native-issues-25594

and it seems to be working as intended: the TextInput components won't respond to touch when scrolling.

Can you provide a Snack/repository where you encounter this issue? This would help to reproduce it.

Aiiros commented 5 years ago

Hi @RobinCsl , thanks for answering.

After your example i stripped down my code to find out that textAlign="center" was causing all of this. Of course i need to keep it :/

expo exemple : https://snack.expo.io/@aiiros/react-native-issue-25594

markus-utke commented 5 years ago

Exact same issue here, without textAlign="center" everything works fine. I also noticed that it will work if you set multiline={true}, however I need it to be single line

markus-utke commented 5 years ago

Also I am on a mac, so I guess we can remove the Linux tag?

markus-utke commented 5 years ago

@RobinCsl I quickly changed your snack to show the issue. For the textInputs that are centering their text the scrolling doesn't work.

https://snack.expo.io/@markuscosinus/https:-github.com-facebook-react-native-issues-25594

RobinCsl commented 5 years ago

@markuscosinus and this happens only on Android, right?

style={{textAlign: "right"}} shows the same behaviour as style={{textAlign: "center"}}. However, style={{textAlign: "left"}} works fine.

And yes, multiline={true} with style={{textAlign: "center"}} makes it work too.

Might be time to dig into the native code deciding on this behaviour! 🙂

markus-utke commented 5 years ago

I don't have an iOS device, but it works fine on the simulator.

Might be time to dig into the native code deciding on this behaviour! 🙂

That would be amazing. Thanks a lot!

RobinCsl commented 5 years ago

It seems like this would be the place where touch events are handled: https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java#L156-L179

@Override
  public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
      case MotionEvent.ACTION_DOWN:
        mDetectScrollMovement = true;
        // Disallow parent views to intercept touch events, until we can detect if we should be
        // capturing these touches or not.
        this.getParent().requestDisallowInterceptTouchEvent(true);
        break;
      case MotionEvent.ACTION_MOVE:
        if (mDetectScrollMovement) {
          if (!canScrollVertically(-1)
              && !canScrollVertically(1)
              && !canScrollHorizontally(-1)
              && !canScrollHorizontally(1)) {
            // We cannot scroll, let parent views take care of these touches.
            this.getParent().requestDisallowInterceptTouchEvent(false);
          }
          mDetectScrollMovement = false;
        }
        break;
    }
    return super.onTouchEvent(ev);
  }

I don't know Java enough, but my guess is that setting the alignment to center or right somehow makes the component think that it can scroll vertically or horizontally. I'm referring to this block: https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java#L167-L173

          if (!canScrollVertically(-1)
              && !canScrollVertically(1)
              && !canScrollHorizontally(-1)
              && !canScrollHorizontally(1)) {
            // We cannot scroll, let parent views take care of these touches.
            this.getParent().requestDisallowInterceptTouchEvent(false);
          }

and searching the whole codebase for canScrollVertically or for canScrollHorizontally does not yield anything apart from the occurrences in this file.

I must say I'm a bit confused!

markus-utke commented 5 years ago

I don't know Java enough, but my guess is that setting the alignment to center or right somehow makes the component think that it can scroll vertically or horizontally.

That sounds logical.

and searching the whole codebase for canScrollVertically or for canScrollHorizontally does not yield anything apart from the occurrences in this file

canScrollHorizontally seems to be an method provided by android: https://developer.android.com/reference/android/view/View.html#canScrollHorizontally(int)

But I have no idea, why it would return true just because of the text alignment

RobinCsl commented 5 years ago

Okay, I think I found a solution!

I will create a PR later today!

Aiiros commented 5 years ago

Any updates ?

RobinCsl commented 5 years ago

I created a PR 30 days ago and it hasn’t been reviewed yet. I don’t know if I should tag someone specifically to review it?

daveyjones commented 5 years ago

@RobinCsl Would your PR also fix this issue I opened a couple days ago?

https://github.com/facebook/react-native/issues/26526

If so, I can close that issue and include my snack.io examples in the comments here.

stale[bot] commented 4 years ago

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.

daveyjones commented 4 years ago

Don't close this issue. It's a major one and definitely deserves attention.

edreyyo commented 4 years ago

@RobinCsl Do you know if your fix ever found its way into a release?

RobinCsl commented 4 years ago

Hi @edreyyo, as you can see, my PR is still open and I did not update it in a while since I've been busy. Feel free to push it further!

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

stale[bot] commented 4 years ago

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.

daveyjones commented 4 years ago

This is an important issue and still needs attention.

fabOnReact commented 4 years ago

I am working on a pull request https://github.com/facebook/react-native/pull/25749#discussion_r433079311

hosseinmd commented 4 years ago
<TextInput
      multiline={true}
      numberOfLines={1}
    />

Set multiline=true and limit the numberOfLines can solve this problem temporarily

stale[bot] commented 4 years ago

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.

daveyjones commented 4 years ago

This is an important issue and still needs attention.

edreyyo commented 3 years ago

Any progress with your PR, @fabriziobertoglio1987?

fabOnReact commented 3 years ago

@edreyyo I found a solution to this issue and included it in pr https://github.com/facebook/react-native/pull/29025

The problem is that my solution is a workaround, I have to disable the textAlign Center when editing the input field as some Android callbacks do not work with gravity Center on Android.

For this reason, my pr could cause rather then solve issues. Thanks.

edreyyo commented 3 years ago

@fabriziobertoglio1987 Alright, thanks for the update. Hopefully there's a fix available soon.

PoLePanda commented 3 years ago

I fix this temporary with this props (if this can help some one else)

multiline={true} numberOfLines={1} blurOnSubmit={true} returnKeyType={"done"}

AbhilashZemoso commented 3 years ago

I fix this temporary with this props (if this can help some one else)

multiline={true} numberOfLines={1} blurOnSubmit={true} returnKeyType={"done"}

Thanks a lot, it is working

SarvaDev-123 commented 3 years ago

Does this fix have any predictions for leaving? I tried this temporary fix but to no avail: multiline={true} numberOfLines={1} blurOnSubmit={true} returnKeyType={"done"}

Edit: I change the height the textinput and solved my problems

height is fail in case of Hebrew language or when you performing rtl activity.

alimo commented 3 years ago

I had the exact same issue. In my case, the problem was the default vertical padding in text inputs.

This padding takes some space and makes the input content scrollable. This is problematic for the outer ScrollView because it thinks you're trying to scroll the input content.

I fixed the issue by adding a paddingVertical: 0 style to my text inputs.

AlirezaHadjar commented 3 years ago

Can't we solve this without multiline = true ?

oyylumo commented 2 years ago

has this still not been fixed?

pdlm95 commented 2 years ago

Any news on this issue?

TomasSestak commented 2 years ago

still major issue

rvenky125 commented 2 years ago

Can't we solve this without multiline = true ?

I'm still having the issue event if tried all those. Does any one have a better solution

pdlm95 commented 2 years ago

@rvenky125 I figured out that editable prop when is set to false is the cause of the scroll issue, so I solved it (kinda) by adding a readOnly prop and a validation in onChangeText method.

<ChildFieldText editable={true} multiline={true} numberOfLines={2} readOnly {...props} />

And in parent component:

onChangeText = (e: any) => {
    if (this.props.readOnly) return;
   ...
}

It's not the best solution but it works for me

rvenky125 commented 2 years ago

@rvenky125 I figured out that editable prop when is set to false is the cause of the scroll issue, so I solved it (kinda) by adding a readOnly prop and a validation in onChangeText method.

<ChildFieldText editable={true} multiline={true} numberOfLines={2} readOnly {...props} />

And in parent component:

onChangeText = (e: any) => {
    if (this.props.readOnly) return;
   ...
}

It's not the best solution but it works for me

Thanks for your reply. But in my case, there is no need to change the editable. It's always true to me. Still, I'm having the problem.

1mehdifaraji commented 2 years ago

I solved the issue by including these properties to the TextInput :

multiline
numberOfLines={1}

This issue is only on android devices only . Wish they fix this issue later on .

The pitfall of doing this is you won't be able to apply password hidden characters on input so the prop called secureTextEntry={true} won't work and I did a workaround not to apply multiline when secureTextEntry is a must like this :

  <TextInput
        ...
        multiline={!secureTextEntry}
        secureTextEntry={secureTextEntry}
      />
AlirezaHadjar commented 2 years ago

Multiline is not a proper solution because the return button on keyboard changes from default and also you wont be able to apply password type

lucassouza16 commented 1 year ago

So far it's serving me well:

https://github.com/facebook/react-native/issues/12167#issuecomment-1343804368

lucassouza16 commented 1 year ago

Thank you, your tip helped me to solve the problem in my case, as on android it does not use the files from the node_modules folder changing the files directly there had no effect, so I tried to build react native from source as instructed on the website: https://reactnative.dev/contributing/how-to-build-from-source to apply the fix, but I wasn't successful, maybe because the page is out of date, so I improvised and encapsulated the entire TextInput component in a module and changed the code snippet in question https://github.com/lucassouza16/react-native-reanimated-textinput/compare/b8c86f9...3b91242#diff-eb7293e9d8fcb1a86324377045b86c30db420d66334740bac6d95401be3a4ac1, the only downside is that the module only works for the react version I extracted it from, but I plan to recreate this component from scratch in case the developers don't solve these bugs in the future, it's sad to think that fixing the problem is so simple, even for me who have little knowledge, but the framework developers neglected it, and even sadder is going to your client and saying that you can't do something t It's not as simple as lining up a text in an input, without leaving usability a tragedy.

dongCode commented 1 year ago

I fix this temporary with this props (if this can help some one else)

multiline={true} numberOfLines={1} blurOnSubmit={true} returnKeyType={"done"}

cool

Shahzaib114 commented 1 year ago

If ScrollView working fine on Android and creating issue on IOS, then simply use scroll view property automaticallyAdjustKeyboardInsets= {true}

Assamese-Boy commented 1 year ago

I am using RN 0.71, I have faced the same issue in my textInput, to solve this don't give any height to the textInput instead use extra view to adjust the heights. Thanks

darimuhittinhey commented 1 year ago

I am using RN 0.71, I have faced the same issue in my textInput, to solve this don't give any height to the textInput instead use extra view to adjust the heights. Thanks

This solved the issue. Just dont give height. Thank you so much dude.

dibyopra commented 1 year ago

I am using RN 0.71, I have faced the same issue in my textInput, to solve this don't give any height to the textInput instead use extra view to adjust the heights. Thanks

its working, instead use minHeight

Jolteon18 commented 9 months ago

In my case, I noticed I was using import {TextInput} from 'react-native-gesture-handler'; instead import {TextInput} from 'react-native';.

Switching from the react-native-gesture-handler to react-native worked for me

react-native-bot commented 3 months ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

AlirezaHadjar commented 3 months ago

Not stale

stochmalm commented 2 months ago

This issue still needs to be fixed.