React Native: TouchableOpacity onPress problems inside a ScrollView

12,994

Solution 1

Set keyboardShouldPersistTaps={true} on your ScrollView.

Duplicate answer here: https://stackoverflow.com/a/34290788/29493

UPDATE: As Hossein writes in his answer, true|false has been deprecated in newer versions in favor of always|never|handled.

Solution 2

Set keyboardShouldPersistTaps='always' to your ScrollView props.

React Native Documentation:

'never' (the default), tapping outside of the focused text input when the keyboard is up dismisses the keyboard. When this happens, children won't receive the tap.

'always', the keyboard will not dismiss automatically, and the scroll view will not catch taps, but children of the scroll view can catch taps.

'handled', the keyboard will not dismiss automatically when the tap was handled by a children, (or captured by an ancestor).

false, deprecated, use 'never' instead.

true, deprecated, use 'always' instead.

Share:
12,994
user3621841
Author by

user3621841

Updated on August 05, 2022

Comments

  • user3621841
    user3621841 over 1 year

    I am running react native 0.24.1 and I am experiencing an issue with the <TouchableOpacity> component when it is placed inside an <ScrollView>.

    Its onPress events fire fine but there is a special case when they do not. If along with the <TouchableOpacity> component you have a <TextInput>, and the current focus is on the <TextInput> box, then you may click on the <TouchableOpacity> and you will see its onPress event WILL NOT be fired.

    At least the first time you do it. Once the focus is NOT on the <TextInput> anymore, you can now press on the <TouchableOpacity> component and its onPress event will fire just fine.

    Note that if the <TouchableOpacity> component is placed inside a <View> instead of an <ScrollView> everything works as expected and the above issue does not apply.

    Here is some code to demonstrate the problem:

    const React = require('react-native');
    const {
      Component,
      Dimensions,
      View,
      ScrollView,
      Text,
      TextInput,
      TouchableOpacity,
    } = React;
    
    
    // ----------------------------------------------------------------------------
    class TouchableOpacityTest extends Component {
      constructor(props, context) {
        super(props, context);
        this.state = {count_onPress:0,count_onPressIn:0,count_onPressOut:0,count_onLongPress:0};
      }
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      onPressEvent(what,e) {
        console.log('what:',what);
        let newState = {};
        newState['count_'+what] = ++this.state['count_'+what];
        this.setState(newState);
      }
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      render() {
        let touchableProps = {
          onPress: this.onPressEvent.bind(this,'onPress'),
          onPressIn: this.onPressEvent.bind(this,'onPressIn'),
          onPressOut: this.onPressEvent.bind(this,'onPressOut'),
          onLongPress: this.onPressEvent.bind(this,'onLongPress'),
        }
    
        return (
          <View style={{flex:1,flexDirection:'column',justifyContent:'flex-start',alignItems:'center',backgroundColor:'blue'}} >
            <ScrollView style={{width:Dimensions.get('window').width*0.9,backgroundColor:'red'}}>
              <TextInput style={{backgroundColor:'rgb(200,200,200)',marginTop:14}}
                placeholder="Focus on me,hide keyboard,and click on text below"
                autoCorrect={false}
              />
              <TouchableOpacity {...touchableProps} >
                <Text style={{fontSize:20,backgroundColor:'pink',marginTop:14}}>
                  Click on me!{"\n"}
                  onPress:{this.state.count_onPress}{"\n"}
                  onPressIn:{this.state.count_onPressIn}{"\n"}
                  onPressOut:{this.state.count_onPressOut}{"\n"}
                  onLongPress:{this.state.count_onLongPress}{"\n"}
                </Text>
              </TouchableOpacity>
            </ScrollView>
          </View>
        );
      }
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    }
    // ----------------------------------------------------------------------------
    AppRegistry.registerComponent('react_native_app1', () => TouchableOpacityTest);
    

    You may replace the <ScrollView> with a <View> component on the above code and you will see that onPress event fires every time, even when the focus is on the <TextView>

    NOTE: I am working on Android. I have no idea if this happens also on iOS.

    NOTE 2: According to Aakash Sigdel, this is indeed happening on iOS too.

  • Hanish Sharma
    Hanish Sharma over 6 years
    Thanks for the help buddy :)
  • FurkanO
    FurkanO over 5 years
    If helps anyone, same problem happened to me only on iPhone X did not happen on iPhone 6 plus