Do not eat taps/clicks in ScrollView when soft-keyboard is detached from viewport

Summary:
If currently focused on a TextInput, clicking an item in a ScrollView takes two clicks.

This is because of `keyboardShouldPersistTaps`, which will fire despite a lack of keyboard events on Android due to special-casing.

This behavior is jarring in scenarios like VR where the soft keyboard is detached from the application. This change avoids eating taps, in this case, where a soft keyboard is open but not inset.

Reviewed By: genkikondo

Differential Revision: D38529237

fbshipit-source-id: a10c5dbf04e6288e0e9e0c805215054bc883339f
This commit is contained in:
Nick Gerleman
2022-08-23 02:25:11 -07:00
committed by Facebook GitHub Bot
parent f5f6896e61
commit fd1e82a10f
@@ -1510,6 +1510,11 @@ class ScrollView extends React.Component<Props, State> {
return false;
}
// Let presses through if the soft keyboard is detached from the viewport
if (this._softKeyboardIsDetached()) {
return false;
}
if (
keyboardNeverPersistTaps &&
this._keyboardIsDismissible() &&
@@ -1548,6 +1553,15 @@ class ScrollView extends React.Component<Props, State> {
return hasFocusedTextInput && softKeyboardMayBeOpen;
};
/**
* Whether an open soft keyboard is present which does not overlap the
* viewport. E.g. for a VR soft-keyboard which is detached from the app
* viewport.
*/
_softKeyboardIsDetached: () => boolean = () => {
return this._keyboardMetrics != null && this._keyboardMetrics.height === 0;
};
/**
* Invoke this from an `onTouchEnd` event.
*
@@ -1556,6 +1570,21 @@ class ScrollView extends React.Component<Props, State> {
_handleTouchEnd: (e: PressEvent) => void = (e: PressEvent) => {
const nativeEvent = e.nativeEvent;
this._isTouching = nativeEvent.touches.length !== 0;
const {keyboardShouldPersistTaps} = this.props;
const keyboardNeverPersistsTaps =
!keyboardShouldPersistTaps || keyboardShouldPersistTaps === 'never';
// Dismiss the keyboard now if we didn't become responder in capture phase
// to eat presses, but still want to dismiss on interaction.
if (
this._softKeyboardIsDetached() &&
this._keyboardIsDismissible() &&
keyboardNeverPersistsTaps
) {
TextInputState.blurTextInput(TextInputState.currentlyFocusedInput());
}
this.props.onTouchEnd && this.props.onTouchEnd(e);
};