18

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.

amb
  • 4,798
  • 6
  • 41
  • 68
user3621841
  • 815
  • 2
  • 10
  • 18
  • try using one of keyboardDismissMode={'none', 'ondrag','interactive'} – Mihir Apr 25 '16 at 04:57
  • I checked it on iOS and can confirm that this happens in iOS too. – Aakash Sigdel Apr 25 '16 at 06:01
  • I had a similar problem with a next to a ScrollView, but the problem was not fixed when removing the ScrollView. Instead, I increased the size of my button to the minimum recommended size of 44x44. After that, the button recognized all tap events. – Adam Loving May 10 '16 at 22:57
  • 1
    Possible duplicate of [TouchableOpacity as Item in ListView only reacts after TextInput has lost focus](http://stackoverflow.com/questions/34290787/touchableopacity-as-item-in-listview-only-reacts-after-textinput-has-lost-focus) – Tim Scott Sep 01 '16 at 20:46

3 Answers3

21

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.

Tim Scott
  • 15,106
  • 9
  • 65
  • 79
11

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.

Hossein
  • 3,755
  • 2
  • 29
  • 39
  • 1
    If helps anyone, same problem happened to me only on `iPhone X` did not happen on `iPhone 6 plus` – FurkanO Dec 21 '18 at 16:16
0

In my case, I was using alignItems:'baseline', when I switched to alignItems:'center', it started working smoothly. Don't know why

Sardar Usama
  • 97
  • 1
  • 11