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

TextInput with textAlign='right' inside a ScrollView gets focused on scroll (Android only)

Open mmazzarolo opened this issue 8 years ago • 63 comments
trafficstars

Description

Hello there, I've found a small issue on Android.
When a TextInput with has textAlign: 'right' inside a ScrollView and you press on it for scrolling it will focus instead (only on Android).
The correct behaviour would be to get focused only if you tap on it (without scrolling).
It works perfectly on iOS or if you remove the textAlign style.

EDIT: I'm having the same issue with textAlign: 'center'.
Works correctly with every other prop (left, justify, auto).

Reproduction

You can test it easily:

<ScrollView>
  <TextInput style={{ textAlign: 'right' }} />
  <View style={{ height: 2000 }} />
</ScrollView>

Additional Information

  • React Native version: 0.40
  • Platform: Android (tested on an emulated Nexus 5 and on real Moto G3)
  • Operating System: MacOS

mmazzarolo avatar Feb 02 '17 13:02 mmazzarolo

I just tested with react-native 0.40.0 and cannot reproduce the problem. Which Android version are you running in your devices? scroll

hoangpham95 avatar Feb 02 '17 17:02 hoangpham95

That's weird. Are you starting the scroll by tapping the textinput?
Also, is that a blank project?
I'm on 5.1.0.

Oh, and thank you for trying it man!

mmazzarolo avatar Feb 02 '17 17:02 mmazzarolo

Yes, this is a blank project. I'm starting outside of the TextInput. If you tap the text input then it should be focused, so I think this might not be an issue.

hoangpham95 avatar Feb 02 '17 18:02 hoangpham95

Ah-ha, there it is!
Nope, it should not be focused because:

  1. If you remove the textAlign prop it doesn't get focused
  2. On iOS it doesn't get focused
  3. On many different native apps I tried it doesn't get focused (for example try the form in the new contact screen in Android)

Thank you anyway :)

mmazzarolo avatar Feb 02 '17 18:02 mmazzarolo

You're right, I tried and saw the problem. The textAlign caused the text input to be focused on touch.

hoangpham95 avatar Feb 02 '17 18:02 hoangpham95

I have the same problem on react-native 0.45.1

AndyJinSS avatar Jul 05 '17 09:07 AndyJinSS

+1 No one can solve this problem?

igofind avatar Jul 11 '17 06:07 igofind

+1 multiline={true} keyboardType={"default"} and limit the maxLength can solve this problem temporarily @igofind

pecopeco avatar Jul 11 '17 07:07 pecopeco

+1 @pecopeco just made my day. thank you for the workaround! Any idea how we can get around the keyboard limitation of it having to be 'default' and not 'numeric'?

turlac avatar Jul 13 '17 02:07 turlac

@pecopeco Thanks ! It works!

igofind avatar Jul 14 '17 05:07 igofind

@pecopeco works but NOT on keyboardType={"numeric"}

kengjungwa avatar Jul 31 '17 07:07 kengjungwa

+1 Same issue!

ahmetacikgoz avatar Jul 31 '17 07:07 ahmetacikgoz

@pecopeco: thanks for the workaround. We can't use multiline though. Any idea for a workaround w/o multilines?

programmdesign avatar Aug 04 '17 10:08 programmdesign

+1 Same Issue

enamin avatar Aug 29 '17 06:08 enamin

+1

Anyone willing to help?

yuvalsegev avatar Sep 05 '17 21:09 yuvalsegev

I solved this issue by installing a PanResponder:

  componentWillMount: function() {
    this._panResponder = PanResponder.create({
      // Ask to be the responder:
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

      onPanResponderGrant: (evt, gestureState) => {
        // The gesture has started. Show visual feedback so the user knows
        // what is happening!

        // gestureState.d{x,y} will be set to zero now
      },
      onPanResponderMove: (evt, gestureState) => {
        // The most recent move distance is gestureState.move{X,Y}

        // The accumulated gesture distance since becoming responder is
        // gestureState.d{x,y}
      },
      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderRelease: (evt, gestureState) => {
        // The user has released all touches while this view is the
        // responder. This typically means a gesture has succeeded
      },
      onPanResponderTerminate: (evt, gestureState) => {
        // Another component has become the responder, so this gesture
        // should be cancelled
      },
      onShouldBlockNativeResponder: (evt, gestureState) => {
        // Returns whether this component should block native components from becoming the JS
        // responder. Returns true by default. Is currently only supported on android.
        return true;
      },
    });
  },

Then on your main view:

 <View {...this._panResponder.panHandlers} />

moughxyz avatar Sep 15 '17 21:09 moughxyz

@pecopeco Thanks mate that worked like a charm. Weird issue really.

nishiltamboli avatar Oct 07 '17 15:10 nishiltamboli

For the record, The TextInput component is rendered inside of a TouchableWithoutFeedback that focuses on press, so I'm not sure how long any of these workarounds will last:

https://github.com/facebook/react-native/blob/master/Libraries/Components/TextInput/TextInput.js#L799

You might also be able to subclass TextInput, override the render method, and remove the Touchable wrapper.

moughxyz avatar Oct 07 '17 16:10 moughxyz

same issue for me, my textInput is numeric and i don't want a multiLine textinput

derakhshanfar avatar Oct 31 '17 10:10 derakhshanfar

@mobitar could you write example please?

derakhshanfar avatar Oct 31 '17 10:10 derakhshanfar

same problem, has some solution ?

aizigao avatar Nov 20 '17 07:11 aizigao

any solution?!

derakhshanfar avatar Nov 23 '17 21:11 derakhshanfar

@derakhshanfar did you have resolved this problem?

yqz0203 avatar Dec 26 '17 11:12 yqz0203

+1 I also have the same issue when manually setting the height of the text input under the default height. This causes it to be vertically scrollable, and eat the ScrollView scroll action. Having the height set like that, removing the textAlign prop or the workaround proposed by @pecopeco aren't even working.

louislatreille avatar Jan 02 '18 20:01 louislatreille

@yqz0203 according to this issue #15274 i think the problem is related to this but i couldn't fix it yet!

However, sometimes a parent will want to make sure that it becomes responder. This can be handled by using the capture phase. Before the responder system bubbles up from the deepest component, it will do a capture phase, firing on*ShouldSetResponderCapture. So if a parent View wants to prevent the child from becoming responder on a touch start, it should have a onStartShouldSetResponderCapture handler which returns true.

derakhshanfar avatar Jan 06 '18 12:01 derakhshanfar

I have the same problem on react-native 0.45.1

yanhaijing avatar Jan 16 '18 08:01 yanhaijing

I have the similar issue with RN 0.49.5 When there is a placeholder for a TextInput with AlignText = 'right', touch on it and move the finger away, the placeholder will disappeared.

feong avatar Jan 29 '18 09:01 feong

Just wrap all your content in TouchableOpacity with activeOpacity={1} props.

Tankerxyz avatar Feb 21 '18 16:02 Tankerxyz

Setup:

"react": "16.0.0",
"react-native": "0.49.3",

Number input component:

focus = () => {
  if (this.inputRef) {
    this.inputRef.focus();
  }
}

inputRef: ?TextInput;

assignRef = (inputRef: ?TextInput) => {
  if (inputRef) {
    this.inputRef = inputRef;
  }
}

render() {
  return (
    <TextInput
      keyboardType="numeric"
      ref={inputRef => this.assignRef(inputRef)}
      {...this.props}
    />
  );
}

Form component:

handleInputPress = () => {
  if (this.input) {
    this.input.focus();
  }
}

input: ?NumberInput;

assignNumberInputRef = (inputRef: ?NumberInput) => {
  if (inputRef) {
    this.input = inputRef;
  }
}

render() {
  return (
    <ScrollView>
      <TouchableOpacity activeOpacity={1} onPress={this.handleInputPress}>
        <View pointerEvents="none">
          <NumberInput
            ref={input => this.assignNumberInputRef(input)}
            textAlign="right"
            ...
          />
        </View>
      </TouchableOpacity>
    </ScrollView>
  )
}

thgala avatar May 07 '18 15:05 thgala

@thgala can you show your NumberInput

SunSargent avatar May 07 '18 15:05 SunSargent