Skip to content

Commit 77cc9d4

Browse files
authored
Merge pull request #3 from chrispader/fix/scroll-to-input-on-open
Feat: Scroll to TextInput onOpen picker
2 parents ce73e0b + 0f1991d commit 77cc9d4

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"lodash.isequal": "^4.5.0"
2828
},
2929
"devDependencies": {
30+
"@react-native-picker/picker": ">=2.1.0",
3031
"@types/react-native": "^0.60.22",
3132
"babel-jest": "^23.6.0",
3233
"babel-preset-react-native": "^4.0.1",
@@ -43,7 +44,6 @@
4344
"react": "16.6.1",
4445
"react-dom": "^16.6.1",
4546
"react-native": "0.57.7",
46-
"@react-native-picker/picker": ">=2.1.0",
4747
"react-test-renderer": "^16.6.1"
4848
},
4949
"peerDependencies": {

src/index.js

+33
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import PropTypes from 'prop-types';
44
import isEqual from 'lodash.isequal';
55
import { Picker } from '@react-native-picker/picker';
66
import { defaultStyles } from './styles';
7+
import { 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;
712

813
export default class RNPickerSelect extends PureComponent {
914
static propTypes = {
@@ -31,6 +36,8 @@ export default class RNPickerSelect extends PureComponent {
3136
onOpen: PropTypes.func,
3237
useNativeAndroidPickerStyle: PropTypes.bool,
3338
fixAndroidTouchableBug: PropTypes.bool,
39+
scrollViewRef: PropTypes.any,
40+
scrollViewContentOffsetY: PropTypes.number,
3441

3542
// Custom Modal props (iOS only)
3643
doneText: PropTypes.string,
@@ -137,6 +144,7 @@ export default class RNPickerSelect extends PureComponent {
137144
this.onValueChange = this.onValueChange.bind(this);
138145
this.onOrientationChange = this.onOrientationChange.bind(this);
139146
this.setInputRef = this.setInputRef.bind(this);
147+
this.scrollToInput = this.scrollToInput.bind(this);
140148
this.togglePicker = this.togglePicker.bind(this);
141149
this.renderInputAccessoryView = this.renderInputAccessoryView.bind(this);
142150
}
@@ -214,12 +222,37 @@ export default class RNPickerSelect extends PureComponent {
214222
return {};
215223
}
216224

225+
scrollToInput() {
226+
if (
227+
this.props.scrollViewRef == null ||
228+
this.props.scrollViewContentOffsetY == null ||
229+
this.inputRef == null
230+
) {
231+
return;
232+
}
233+
234+
this.inputRef.measureInWindow((_x, y, _width, height) => {
235+
// Bottom y-position of TextInput on screen
236+
const textInputBottomY = y + height;
237+
// Top y-position of picker modal on screen
238+
const modalY = Dimensions.get('window').height - IOS_MODAL_HEIGHT;
239+
240+
// If TextInput is below picker modal, scroll up
241+
if (textInputBottomY > modalY) {
242+
this.props.scrollViewRef.current.scrollTo({
243+
y: textInputBottomY - modalY + this.props.scrollViewContentOffsetY,
244+
});
245+
}
246+
});
247+
}
248+
217249
triggerOpenCloseCallbacks() {
218250
const { onOpen, onClose } = this.props;
219251
const { showPicker } = this.state;
220252

221253
if (!showPicker && onOpen) {
222254
onOpen();
255+
this.scrollToInput();
223256
}
224257

225258
if (showPicker && onClose) {

0 commit comments

Comments
 (0)