From 35cc5b8460c318ccd532b056fa8390b92a942f09 Mon Sep 17 00:00:00 2001 From: Wojciech Stanisz <42337257+wojtus7@users.noreply.github.com> Date: Wed, 23 Oct 2019 18:23:46 +0200 Subject: [PATCH] fix: handle keyboard return for short interactions (#272) When user has super short swiping interaction it's an issue that keyboard won't reappear on screen. That's because there is short time when system will make sure to hide keyboard no matter what. Too fast text input refocus will result only in keyboard flashing on screen and hiding right away. For such short interactions I created a delay that will ensure that the keyboard will reappear on the screen every time and make sure it's executed only when needed. It only affect super short interactions <100ms to make sure they work correctly, and doesn't affect any logic beyond that. As far as my research go it seems that the react-navigation isn't responsible for hiding the Keyboard in that specific case, so I don't think we can simply prevent this action when we don't want it. Doing the check in KeyboardMenager and delaying it is the safest way IMO - we make sure that it won't affect any other logic than concerning keyboard itself. (It would happen if we prevent the action somewhere else like in StackItem) Tested on physical iOS device, iOS simulator, and Android device with both app using the library and library's example app. --- src/views/KeyboardManager.tsx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/views/KeyboardManager.tsx b/src/views/KeyboardManager.tsx index 01721bb4d..4e8dcfe27 100644 --- a/src/views/KeyboardManager.tsx +++ b/src/views/KeyboardManager.tsx @@ -13,6 +13,7 @@ export default class KeyboardManager extends React.Component { // Numeric id of the previously focused text input // When a gesture didn't change the tab, we can restore the focused input with this private previouslyFocusedTextInput: number | null = null; + private startTimestamp: number = 0; private handlePageChangeStart = () => { const input = TextInput.State.currentlyFocusedField(); @@ -22,6 +23,9 @@ export default class KeyboardManager extends React.Component { // Store the id of this input so we can refocus it if change was cancelled this.previouslyFocusedTextInput = input; + + // Store timestamp for touch start + this.startTimestamp = Date.now(); }; private handlePageChangeConfirm = () => { @@ -36,10 +40,23 @@ export default class KeyboardManager extends React.Component { const input = this.previouslyFocusedTextInput; if (input) { - TextInput.State.focusTextInput(input); - } + // If the interaction was super short we should make sure keyboard won't hide again. - this.previouslyFocusedTextInput = null; + // Too fast input refocus will result only in keyboard flashing on screen and hiding right away. + // During first ~100ms keyboard will be dismissed no matter what, + // so we have to make sure it won't interrupt input refocus logic. + // That's why when the interaction is shorter than 100ms we add delay so it won't hide once again. + // Subtracting timestamps makes us sure the delay is executed only when needed. + if (Date.now() - this.startTimestamp < 100) { + setTimeout(() => { + TextInput.State.focusTextInput(input); + this.previouslyFocusedTextInput = null; + }, 100); + } else { + TextInput.State.focusTextInput(input); + this.previouslyFocusedTextInput = null; + } + } }; render() {