11import * as React from 'react' ;
2- import { StyleSheet , Keyboard , I18nManager } from 'react-native' ;
2+ import { StyleSheet , TextInput , Keyboard , I18nManager } from 'react-native' ;
33import { PanGestureHandler , State } from 'react-native-gesture-handler' ;
44import Animated , { Easing } from 'react-native-reanimated' ;
55import memoize from './memoize' ;
@@ -215,6 +215,12 @@ export default class Pager<T extends Route> extends React.Component<Props<T>> {
215215 // Remember to set it before transition needs to occur
216216 private isSwipeGesture : Animated . Value < Binary > = new Value ( FALSE ) ;
217217
218+ // Track the index value when a swipe gesture has ended
219+ // This lets us know if a gesture end triggered a tab switch or not
220+ private indexAtSwipeEnd : Animated . Value < number > = new Value (
221+ this . props . navigationState . index
222+ ) ;
223+
218224 // Mappings to some prop values
219225 // We use them in animation calculations, so we need live animated nodes
220226 private routesLength = new Value ( this . props . navigationState . routes . length ) ;
@@ -291,6 +297,10 @@ export default class Pager<T extends Route> extends React.Component<Props<T>> {
291297 // It also needs to be reset right after componentDidUpdate fires
292298 private pendingIndexValue : number | undefined = undefined ;
293299
300+ // Numeric id of the previously focused text input
301+ // When a gesture didn't change the tab, we can restore the focused input with this
302+ private previouslyFocusedTextInput : number | null = null ;
303+
294304 // Listeners for the entered screen
295305 private enterListeners : Listener [ ] = [ ] ;
296306
@@ -301,7 +311,7 @@ export default class Pager<T extends Route> extends React.Component<Props<T>> {
301311 } ;
302312
303313 private jumpTo = ( key : string ) => {
304- const { navigationState } = this . props ;
314+ const { navigationState, keyboardDismissMode , onIndexChange } = this . props ;
305315
306316 const index = navigationState . routes . findIndex ( route => route . key === key ) ;
307317
@@ -311,7 +321,13 @@ export default class Pager<T extends Route> extends React.Component<Props<T>> {
311321 if ( navigationState . index === index ) {
312322 this . jumpToIndex ( index ) ;
313323 } else {
314- this . props . onIndexChange ( index ) ;
324+ onIndexChange ( index ) ;
325+
326+ // When the index changes, the focused input will no longer be in current tab
327+ // So we should dismiss the keyboard
328+ if ( keyboardDismissMode === 'auto' ) {
329+ Keyboard . dismiss ( ) ;
330+ }
315331 }
316332 } ;
317333
@@ -471,19 +487,43 @@ export default class Pager<T extends Route> extends React.Component<Props<T>> {
471487 // Listen to updates for this value only when it changes
472488 // Without `onChange`, this will fire even if the value didn't change
473489 // We don't want to call the listeners if the value didn't change
474- call ( [ this . isSwiping ] , ( [ value ] : readonly Binary [ ] ) => {
475- const { keyboardDismissMode, onSwipeStart, onSwipeEnd } = this . props ;
476-
477- if ( value === TRUE ) {
478- onSwipeStart && onSwipeStart ( ) ;
479-
480- if ( keyboardDismissMode === 'on-drag' ) {
481- Keyboard . dismiss ( ) ;
490+ call (
491+ [ this . isSwiping , this . indexAtSwipeEnd , this . index ] ,
492+ ( [ isSwiping , indexAtSwipeEnd , currentIndex ] : readonly number [ ] ) => {
493+ const { keyboardDismissMode, onSwipeStart, onSwipeEnd } = this . props ;
494+
495+ if ( isSwiping === TRUE ) {
496+ onSwipeStart && onSwipeStart ( ) ;
497+
498+ if ( keyboardDismissMode === 'auto' ) {
499+ const input = TextInput . State . currentlyFocusedField ( ) ;
500+
501+ // When a gesture begins, blur the currently focused input
502+ TextInput . State . blurTextInput ( input ) ;
503+
504+ // Store the id of this input so we can refocus it if gesture was cancelled
505+ this . previouslyFocusedTextInput = input ;
506+ } else if ( keyboardDismissMode === 'on-drag' ) {
507+ Keyboard . dismiss ( ) ;
508+ }
509+ } else {
510+ onSwipeEnd && onSwipeEnd ( ) ;
511+
512+ if ( keyboardDismissMode === 'auto' ) {
513+ if ( indexAtSwipeEnd === currentIndex ) {
514+ // The index didn't change, we should restore the focus of text input
515+ const input = this . previouslyFocusedTextInput ;
516+
517+ if ( input ) {
518+ TextInput . State . focusTextInput ( input ) ;
519+ }
520+ }
521+
522+ this . previouslyFocusedTextInput = null ;
523+ }
482524 }
483- } else {
484- onSwipeEnd && onSwipeEnd ( ) ;
485525 }
486- } )
526+ )
487527 ) ,
488528 onChange (
489529 this . nextIndex ,
@@ -518,6 +558,7 @@ export default class Pager<T extends Route> extends React.Component<Props<T>> {
518558 ] ,
519559 [
520560 set ( this . isSwiping , FALSE ) ,
561+ set ( this . indexAtSwipeEnd , this . index ) ,
521562 this . transitionTo (
522563 cond (
523564 and (
0 commit comments