Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native: TouchableOpacity onPress problems inside a ScrollView

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.

like image 464
user3621841 Avatar asked Apr 24 '16 11:04

user3621841


2 Answers

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.

like image 119
Tim Scott Avatar answered Sep 28 '22 23:09

Tim Scott


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.

like image 28
Hossein Avatar answered Sep 28 '22 23:09

Hossein