Skip to content

Commit 6d2a527

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Avoid eating clicks/taps into ScrollView when using physical keyboard (#30374)
Summary: This is an extension of #29798 which was reverted due to cases where the soft keyboard could not be dismissed. ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [General] [Fixed] - Avoid eating clicks/taps into ScrollView when using physical keyboard Pull Request resolved: #30374 Test Plan: Validated with iOS simulator that taps on default ScrollView will dismiss soft keyboard and be eaten if open, but taps are not eaten when emulating a connected physical keyboard. Reviewed By: kacieb Differential Revision: D24935077 Pulled By: lyahdav fbshipit-source-id: 19d9cf64547e40a35f9363896e3abbdccb95b546
1 parent eaab647 commit 6d2a527

File tree

1 file changed

+28
-4
lines changed

1 file changed

+28
-4
lines changed

Libraries/Components/ScrollResponder.js

+28-4
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ const ScrollResponderMixin = {
186186

187187
if (
188188
this.props.keyboardShouldPersistTaps === 'handled' &&
189-
currentlyFocusedInput != null &&
189+
this.scrollResponderKeyboardIsDismissible() &&
190190
e.target !== currentlyFocusedInput
191191
) {
192192
return true;
@@ -223,7 +223,6 @@ const ScrollResponderMixin = {
223223
// and a new touch starts with a non-textinput target (in which case the
224224
// first tap should be sent to the scroll view and dismiss the keyboard,
225225
// then the second tap goes to the actual interior view)
226-
const currentlyFocusedTextInput = TextInputState.currentlyFocusedInput();
227226
const {keyboardShouldPersistTaps} = this.props;
228227
const keyboardNeverPersistTaps =
229228
!keyboardShouldPersistTaps || keyboardShouldPersistTaps === 'never';
@@ -240,7 +239,7 @@ const ScrollResponderMixin = {
240239

241240
if (
242241
keyboardNeverPersistTaps &&
243-
currentlyFocusedTextInput != null &&
242+
this.scrollResponderKeyboardIsDismissible() &&
244243
e.target != null &&
245244
!TextInputState.isTextInput(e.target)
246245
) {
@@ -250,6 +249,31 @@ const ScrollResponderMixin = {
250249
return false;
251250
},
252251

252+
/**
253+
* Do we consider there to be a dismissible soft-keyboard open?
254+
*/
255+
scrollResponderKeyboardIsDismissible: function(): boolean {
256+
const currentlyFocusedInput = TextInputState.currentlyFocusedInput();
257+
258+
// We cannot dismiss the keyboard without an input to blur, even if a soft
259+
// keyboard is open (e.g. when keyboard is open due to a native component
260+
// not participating in TextInputState). It's also possible that the
261+
// currently focused input isn't a TextInput (such as by calling ref.focus
262+
// on a non-TextInput).
263+
const hasFocusedTextInput =
264+
currentlyFocusedInput != null &&
265+
TextInputState.isTextInput(currentlyFocusedInput);
266+
267+
// Even if an input is focused, we may not have a keyboard to dismiss. E.g
268+
// when using a physical keyboard. Ensure we have an event for an opened
269+
// keyboard, except on Android where setting windowSoftInputMode to
270+
// adjustNone leads to missing keyboard events.
271+
const softKeyboardMayBeOpen =
272+
this.keyboardWillOpenTo != null || Platform.OS === 'android';
273+
274+
return hasFocusedTextInput && softKeyboardMayBeOpen;
275+
},
276+
253277
/**
254278
* Invoke this from an `onResponderReject` event.
255279
*
@@ -324,7 +348,7 @@ const ScrollResponderMixin = {
324348
if (
325349
this.props.keyboardShouldPersistTaps !== true &&
326350
this.props.keyboardShouldPersistTaps !== 'always' &&
327-
currentlyFocusedTextInput != null &&
351+
this.scrollResponderKeyboardIsDismissible() &&
328352
e.target !== currentlyFocusedTextInput &&
329353
!this.state.observedScrollSinceBecomingResponder &&
330354
!this.state.becameResponderWhileAnimating

0 commit comments

Comments
 (0)