@@ -5,16 +5,17 @@ import isEqual from 'lodash.isequal';
55import { Picker } from '@react-native-picker/picker' ;
66import { defaultStyles } from './styles' ;
77import { Dimensions } from 'react-native' ;
8-
9- // Measuring the modal before rendering is not working reliably, so we need to hardcode the height
10- // This height was tested thoroughly on several iPhone Models (from iPhone 8 to 14 Pro)
11- const IOS_MODAL_HEIGHT = 262 ;
8+ import { PickerAvoidingView } from './PickerAvoidingView' ;
9+ import { PickerStateContext , PickerStateProvider } from './PickerStateProvider' ;
10+ import { IOS_MODAL_HEIGHT } from './constants' ;
1211
1312const preserveSpaces = ( label ) => {
1413 return label . replace ( / / g, '\u00a0' ) ;
1514} ;
1615
1716export default class RNPickerSelect extends PureComponent {
17+ static contextType = PickerStateContext ;
18+
1819 static propTypes = {
1920 onValueChange : PropTypes . func . isRequired ,
2021 items : PropTypes . arrayOf (
@@ -245,23 +246,34 @@ export default class RNPickerSelect extends PureComponent {
245246 // If TextInput is below picker modal, scroll up
246247 if ( textInputBottomY > modalY ) {
247248 this . props . scrollViewRef . current . scrollTo ( {
248- y : textInputBottomY - modalY + this . props . scrollViewContentOffsetY ,
249+ // Add 10 pixels for a more visually pleasant effect
250+ y : textInputBottomY + 10 - modalY + this . props . scrollViewContentOffsetY ,
249251 } ) ;
250252 }
251253 } ) ;
252254 }
253255
254- triggerOpenCloseCallbacks ( ) {
256+ triggerCallbacks ( ) {
255257 const { onOpen, onClose } = this . props ;
256258 const { showPicker } = this . state ;
257259
258260 if ( ! showPicker && onOpen ) {
259261 onOpen ( ) ;
260- this . scrollToInput ( ) ;
261262 }
262263
263- if ( showPicker && onClose ) {
264- onClose ( ) ;
264+ if ( showPicker ) {
265+ if ( onClose ) {
266+ onClose ( ) ;
267+ }
268+
269+ // If the picker is currently shown, toggling it will start closing
270+ // the modal on iOS. Let's handle this here, instead on relying on
271+ // Modal's onDismiss, because onDismiss is fired _after_ the modal
272+ // closing animation ends. PickerAvoidingView behaves better
273+ // (visually) when it adjusts right after the modal closing starts.
274+ if ( this . context ) {
275+ this . context . setIsModalShown ( false ) ;
276+ }
265277 }
266278 }
267279
@@ -291,7 +303,7 @@ export default class RNPickerSelect extends PureComponent {
291303 return ;
292304 }
293305
294- this . triggerOpenCloseCallbacks ( ) ;
306+ this . triggerCallbacks ( ) ;
295307
296308 if ( Keyboard . isVisible ( ) ) {
297309 const keyboardListener = Keyboard . addListener ( 'keyboardDidHide' , ( ) => {
@@ -481,6 +493,13 @@ export default class RNPickerSelect extends PureComponent {
481493 supportedOrientations = { [ 'portrait' , 'landscape' ] }
482494 onOrientationChange = { this . onOrientationChange }
483495 { ...modalProps }
496+ onShow = { ( ) => {
497+ if ( this . context ) {
498+ this . context . setIsModalShown ( true ) ;
499+ }
500+
501+ this . scrollToInput ( ) ;
502+ } }
484503 >
485504 < TouchableOpacity
486505 style = { [ defaultStyles . modalViewTop , style . modalViewTop ] }
@@ -635,4 +654,4 @@ export default class RNPickerSelect extends PureComponent {
635654 }
636655}
637656
638- export { defaultStyles } ;
657+ export { defaultStyles , PickerStateProvider , PickerAvoidingView } ;
0 commit comments