Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Scroll to TextInput on picker opening #496

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
"/src"
],
"dependencies": {
"@react-native-picker/picker": "^1.8.3",
"lodash.isequal": "^4.5.0"
},
"devDependencies": {
"@react-native-picker/picker": ">=2.1.0",
"@types/react-native": "^0.60.22",
"babel-jest": "^23.6.0",
"babel-preset-react-native": "^4.0.1",
Expand All @@ -52,6 +52,9 @@
"react-native": "0.57.7",
"react-test-renderer": "^16.6.1"
},
"peerDependencies": {
"@react-native-picker/picker": ">=2.1.0"
},
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
Expand Down
45 changes: 44 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import React, { PureComponent } from 'react';
import { Keyboard, Modal, Platform, Text, TextInput, TouchableOpacity, View } from 'react-native';
import {
Keyboard,
Modal,
Platform,
Text,
TextInput,
TouchableOpacity,
View,
Dimensions,
} from 'react-native';
import PropTypes from 'prop-types';
import isEqual from 'lodash.isequal';
import { Picker } from '@react-native-picker/picker';
import { defaultStyles } from './styles';

// Measuring the modal before rendering is not working reliably, so we need to hardcode the height
// This height was tested thoroughly on several iPhone Models (from iPhone 8 to 14 Pro)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tested with iPhone SE / Mini variants too?

also - does landscape mode work?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also - ipads?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it was compatible, but i just made some improvements 👍 🚀

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great. able to add tests?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey, sorry for the late reply...

i think it's difficult to add tests here, because this is basically an iOS specific feature. With jest/enzyme we can only test in a mocked environment.

I added a dummy test, that reflects a test for this functionality, but this will not work in a web environnment

const IOS_MODAL_HEIGHT = 262;

export default class RNPickerSelect extends PureComponent {
static propTypes = {
onValueChange: PropTypes.func.isRequired,
Expand Down Expand Up @@ -33,6 +46,8 @@ export default class RNPickerSelect extends PureComponent {
useNativeAndroidPickerStyle: PropTypes.bool,
fixAndroidTouchableBug: PropTypes.bool,
darkTheme: PropTypes.bool,
scrollViewRef: PropTypes.any,
scrollViewContentOffsetY: PropTypes.number,

// Custom Modal props (iOS only)
doneText: PropTypes.string,
Expand Down Expand Up @@ -88,6 +103,8 @@ export default class RNPickerSelect extends PureComponent {
Icon: null,
InputAccessoryView: null,
darkTheme: false,
scrollViewRef: null,
scrollViewContentOffsetY: 0,
};

static handlePlaceholder({ placeholder }) {
Expand Down Expand Up @@ -140,6 +157,7 @@ export default class RNPickerSelect extends PureComponent {
this.onValueChange = this.onValueChange.bind(this);
this.onOrientationChange = this.onOrientationChange.bind(this);
this.setInputRef = this.setInputRef.bind(this);
this.scrollToInput = this.scrollToInput.bind(this);
this.togglePicker = this.togglePicker.bind(this);
this.renderInputAccessoryView = this.renderInputAccessoryView.bind(this);
}
Expand Down Expand Up @@ -217,6 +235,30 @@ export default class RNPickerSelect extends PureComponent {
return {};
}

scrollToInput() {
if (
this.props.scrollViewRef == null ||
this.props.scrollViewContentOffsetY == null ||
this.inputRef == null
) {
return;
}

this.inputRef.measureInWindow((_x, y, _width, height) => {
// Bottom y-position of TextInput on screen
const textInputBottomY = y + height;
// Top y-position of picker modal on screen
const modalY = Dimensions.get('window').height - IOS_MODAL_HEIGHT;

// If TextInput is below picker modal, scroll up
if (textInputBottomY > modalY) {
this.props.scrollViewRef.current.scrollTo({
y: textInputBottomY - modalY + this.props.scrollViewContentOffsetY,
});
}
});
}

isDarkTheme() {
const { darkTheme } = this.props;

Expand All @@ -229,6 +271,7 @@ export default class RNPickerSelect extends PureComponent {

if (!showPicker && onOpen) {
onOpen();
this.scrollToInput();
}

if (showPicker && onClose) {
Expand Down
12 changes: 6 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -999,10 +999,10 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"

"@react-native-picker/picker@^1.8.3":
version "1.8.3"
resolved "https://registry.yarnpkg.com/@react-native-picker/picker/-/picker-1.8.3.tgz#fcbf969a4add749fc37ef064a5eb55eadc93db39"
integrity sha512-zfr8k9L5BJVN7fIrmrto1cCptZjkGoiKWeZTsCR+XormQnWj0Tqrv0S9Ni3SvdT5JZ2OAQ9H+edMRSUvrAxwQA==
"@react-native-picker/picker@>=2.1.0":
version "2.4.8"
resolved "https://registry.yarnpkg.com/@react-native-picker/picker/-/picker-2.4.8.tgz#a1a21f3d6ecadedbc3f0b691a444ddd7baa081f8"
integrity sha512-5NQ5XPo1B03YNqKFrV6h9L3CQaHlB80wd4ETHUEABRP2iLh7FHLVObX2GfziD+K/VJb8G4KZcZ23NFBFP1f7bg==

"@types/json5@^0.0.29":
version "0.0.29"
Expand Down Expand Up @@ -5488,7 +5488,7 @@ json-schema@0.2.3:
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==

json-stable-stringify@^1.0.1:
version "1.0.1"
Expand Down Expand Up @@ -8381,7 +8381,7 @@ test-exclude@^4.2.1:
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==

throat@^4.0.0, throat@^4.1.0:
version "4.1.0"
Expand Down