@@ -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,7 +246,8 @@ 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 } ) ;
@@ -257,7 +259,6 @@ export default class RNPickerSelect extends PureComponent {
257259
258260 if ( ! showPicker && onOpen ) {
259261 onOpen ( ) ;
260- this . scrollToInput ( ) ;
261262 }
262263
263264 if ( showPicker && onClose ) {
@@ -286,11 +287,21 @@ export default class RNPickerSelect extends PureComponent {
286287
287288 togglePicker ( animate = false , postToggleCallback ) {
288289 const { disabled } = this . props ;
290+ const { showPicker } = this . state ;
289291
290292 if ( disabled ) {
291293 return ;
292294 }
293295
296+ // If the picker is currently shown, toggling it will start closing the
297+ // modal on iOS. Let's handle this here, instead on relying on
298+ // Modal's onDismiss, because onDismiss is fired _after_ the modal
299+ // closing animation ends. PickerAvoidingView behaves better (visually)
300+ // when it adjusts right after the modal closing starts.
301+ if ( showPicker && this . context ) {
302+ this . context . setIsModalShown ( false ) ;
303+ }
304+
294305 this . triggerOpenCloseCallbacks ( ) ;
295306
296307 if ( Keyboard . isVisible ( ) ) {
@@ -481,6 +492,13 @@ export default class RNPickerSelect extends PureComponent {
481492 supportedOrientations = { [ 'portrait' , 'landscape' ] }
482493 onOrientationChange = { this . onOrientationChange }
483494 { ...modalProps }
495+ onShow = { ( ) => {
496+ if ( this . context ) {
497+ this . context . setIsModalShown ( true ) ;
498+ }
499+
500+ this . scrollToInput ( ) ;
501+ } }
484502 >
485503 < TouchableOpacity
486504 style = { [ defaultStyles . modalViewTop , style . modalViewTop ] }
@@ -635,4 +653,4 @@ export default class RNPickerSelect extends PureComponent {
635653 }
636654}
637655
638- export { defaultStyles } ;
656+ export { defaultStyles , PickerStateProvider , PickerAvoidingView } ;
0 commit comments