How to avoid having to click TouchableOpacity twice to trigger onPress event?

Viewed 6887

I'm using this module and the issue is that the Dialogue element that pops up, which is a Modal, has two TouchableOpacity buttons. After typing, when the keyboard is up, clicking the 'submit' TouchableOpacity will first clear/hide the keyboard, and only the second tap on the 'submit' TouchableOpacity will trigger the onPress event. What can I do as a workaround here? I've tried changing it to a Button from react-native and from react-native-elements but it behaves the same way.


Edit:

The component:

    return (
      <Modal
        animationType="fade"
        transparent={true}
        visible={this.props.isDialogVisible}
        onRequestClose={() => {
          this.props.closeDialog();
          this.setState({ inputModal: "" });
        }}
      >
        <View style={[styles.container, { ...modalStyleProps }]}>
          <TouchableOpacity
            style={styles.container}
            activeOpacity={1}
            onPress={() => {
              this.props.closeDialog();
              this.setState({ inputModal: "", openning: true });
            }}
          >
            <View style={[styles.modal_container, { ...dialogStyleProps }]}>
              <View style={styles.modal_body}>
                <Text style={styles.title_modal}>{title}</Text>
                <Text
                  style={[
                    this.props.message ? styles.message_modal : { height: 0 }
                  ]}
                >
                  {this.props.message}
                </Text>
                <TextInput
                  style={styles.input_container}
                  autoCorrect={
                    textProps && textProps.autoCorrect == false ? false : true
                  }
                  autoCapitalize={
                    textProps && textProps.autoCapitalize
                      ? textProps.autoCapitalize
                      : "none"
                  }
                  clearButtonMode={
                    textProps && textProps.clearButtonMode
                      ? textProps.clearButtonMode
                      : "never"
                  }
                  clearTextOnFocus={
                    textProps && textProps.clearTextOnFocus == true
                      ? textProps.clearTextOnFocus
                      : false
                  }
                  keyboardType={
                    textProps && textProps.keyboardType
                      ? textProps.keyboardType
                      : "default"
                  }
                  autoFocus={true}
                  onKeyPress={() => this.setState({ openning: false })}
                  underlineColorAndroid="transparent"
                  placeholder={hintInput}
                  onChangeText={inputModal => {
                    if (this.props.setBackupCommentText) {
                      this.props.setBackupCommentText(inputModal);
                    }

                    this.setState({ inputModal });
                  }}
                  value={value || this.props.backupCommentText}
                  multiline={true}
                />
              </View>
              <View style={styles.btn_container}>
                <TouchableOpacity
                  style={styles.touch_modal}
                  onPress={() => {
                    this.props.closeDialog();
                    this.setState({ inputModal: "", openning: true });
                  }}
                >
                  <Text style={styles.btn_modal_left}>{cancelText}</Text>
                </TouchableOpacity>
                <View style={styles.divider_btn}></View>
                <TouchableOpacity
                  style={styles.touch_modal}
                  onPress={() => {
                    if (
                      this.props.initValueTextInput &&
                      this.props.initValueTextInput.trim().length === 0
                    ) {
                      Toast.show("Comment cannot be empty");
                    } else {
                      this.props.submitInput(value);

                      this.setState({ inputModal: "", openning: true });

                      if (this.props.setBackupCommentText) {
                        this.props.setBackupCommentText("");
                      }
                    }
                  }}
                >
                  <Text style={styles.btn_modal_right}>{submitText}</Text>
                </TouchableOpacity>
              </View>
            </View>
          </TouchableOpacity>
        </View>
      </Modal>
    );
4 Answers

This is likely because a parent scrollview is intercepting the tap gesture. To solve this problem, find the nearest ScrollView or FlatList parent and add the keyboardShouldPersistTaps='handled' attribute. This will prevent the keyboard from auto dismissing on the tap (which consumes the tap). You may need to add Keyboard.dismiss() to get it to work as expected.

<ScrollView keyboardShouldPersistTaps='handled'>

...

</ScrollView>

For FlatList or ScrollView, you can use following props

keyboardShouldPersistTaps={true}

Add keyboardShouldPersistTaps to parent or nearest FlatList or ScrollView,

Determines when the keyboard should stay visible after a tap.

  • 'never' 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 children of the scroll view (or captured by an ancestor).
  • false, deprecated, use 'never' instead
  • true, deprecated, use 'always' instead

reference: https://reactnative.dev/docs/scrollview#keyboardshouldpersisttaps

Just wrap your code inside from react-native-keyboard-aware-scroll-view library

<Modal>
  <KeyboardAwareScrollView>
    ...
  </KeyboardAwareScrollView>
</Modal>

and that's it.

Related