Skip to content

Commit c6211c4

Browse files
committed
🎉 Adds support for auto TextInput onFocus scroll (#22)
* Adds support for auto TextInput onFocus scroll Adds support for auto TextInput onFocus scroll Allow scroll to a specific position (#19) * allow scroll to a specific position * Update KeyboardAwareMixin.js Applied suggestions from @APSL to add the `animated` parameter to this function and specify flow annotations * Improved README
1 parent ffedf32 commit c6211c4

File tree

4 files changed

+72
-27
lines changed

4 files changed

+72
-27
lines changed

README.md

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
# react-native-keyboard-aware-scroll-view
2-
A ScrollView component that handles keyboard appearance.
2+
A ScrollView component that handles keyboard appearance and automatically scrolls to focused `TextInput`.
3+
4+
<p align="center">
5+
<img src="https://raw.githubusercontent.com/wiki/APSL/react-native-keyboard-aware-scroll-view/kasv.gif" alt="Scroll demo" width="400">
6+
</p>
37

48
## Supported versions
5-
Use `react-native>=0.25.0` for `v0.0.7` and `v0.0.6` for older RN versions.
9+
Use `react-native>=0.25.0` for `v0.0.7` & up and `v0.0.6` for older RN versions.
610

711
## Installation
812
Installation can be done through ``npm``:
@@ -32,27 +36,37 @@ import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view
3236
</KeyboardAwareScrollView>
3337
```
3438

35-
The component accepts the experimental prop ``viewIsInsideTabBar``, which tries
36-
to solve resizing issues when rendering inside a ``TabBar`` component.
37-
3839
## Auto-scroll in `TextInput` fields
39-
In order to perform an auto-scroll whenever a `TextInput` field gets focused, you can use the built-in method `scrollToFocusedInput`. Define the following function for each of your `onFocus` event on your inputs:
40+
As of `v0.1.0`, the component auto scrolls to the focused `TextInput` 😎. For versions `v0.0.7` and older you can do the following.
41+
42+
### Programatically scroll to any `TextInput`
43+
In order to scroll to any `TextInput` field, you can use the built-in method `scrollToFocusedInput`. Example:
4044

4145
```js
42-
_scrollToInput (event, reactNode) {
46+
_scrollToInput (reactNode: any) {
4347
// Add a 'scroll' ref to your ScrollView
44-
this.refs.scroll.scrollToFocusedInput(event, reactNode)
48+
this.refs.scroll.scrollToFocusedInput(reactNode)
4549
}
4650
```
4751

4852
```jsx
4953
<KeyboardAwareScrollView ref='scroll'>
5054
<View>
51-
<TextInput ref='myInput' onFocus={this._scrollToInput}/>
55+
<TextInput onFocus={(event: Event) => {
56+
// `bind` the function if you're using ES6 classes
57+
this._scrollToInput(ReactNative.findNodeHandle(event.target))
58+
}/>
5259
</View>
5360
</KeyboardAwareScrollView>
5461
```
5562
63+
### Programatically scroll to any position
64+
There's another built-in function that lets you programatically scroll to any position of the scroll view:
65+
66+
```js
67+
this.refs.scroll.scrollToPosition(0, 0, true)
68+
```
69+
5670
## Register to keyboard events
5771
You can register to `ScrollViewResponder` events `onKeyboardWillShow` and `onKeyboardWillHide`:
5872
@@ -67,6 +81,16 @@ You can register to `ScrollViewResponder` events `onKeyboardWillShow` and `onKey
6781
</KeyboardAwareScrollView>
6882
```
6983
84+
## API
85+
### Props
86+
All the `ScrollView`/`ListView` props will be passed.
87+
88+
| **Prop** | **Type** | **Description** |
89+
|----------|----------|-----------------|
90+
| `viewIsInsideTabBar` | `boolean` | Adds an extra offset that represents the `TabBarIOS` height. |
91+
| `resetScrollToCoords` | `Object: {x: number, y: number}` | Coordinates that will be used to reset the scroll when the keyboard hides. |
92+
93+
7094
## License
7195
7296
MIT.

lib/KeyboardAwareListView.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,22 @@ const KeyboardAwareListView = React.createClass({
88
propTypes: {
99
...ListView.propTypes,
1010
viewIsInsideTabBar: React.PropTypes.bool,
11+
resetScrollToCoords: PropTypes.shape({
12+
x: PropTypes.number,
13+
y: PropTypes.number,
14+
}),
1115
},
1216
mixins: [KeyboardAwareMixin],
1317

14-
componentWillMount: function() {
15-
if (this.props.viewIsInsideTabBar) {
16-
this.setViewIsInsideTabBar(this.props.viewIsInsideTabBar)
17-
}
18+
componentWillMount: function () {
19+
this.setViewIsInsideTabBar(this.props.viewIsInsideTabBar)
20+
this.setResetScrollToCoords(this.props.resetScrollToCoords)
1821
},
1922

2023
render: function () {
2124
return (
2225
<ListView
23-
ref='keyboardView'
26+
ref='_rnkasv_keyboardView'
2427
keyboardDismissMode='interactive'
2528
contentInset={{bottom: this.state.keyboardSpace}}
2629
showsVerticalScrollIndicator={true}

lib/KeyboardAwareMixin.js

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/* @flow */
22

3-
import { DeviceEventEmitter } from 'react-native'
3+
import ReactNative, { TextInput, DeviceEventEmitter } from 'react-native'
44
import TimerMixin from 'react-timer-mixin'
55

66
const _KAM_DEFAULT_TAB_BAR_HEIGHT = 49
7+
const _KAM_KEYBOARD_OPENING_TIME = 250
78

89
const KeyboardAwareMixin = {
910
mixins: [TimerMixin],
@@ -13,6 +14,10 @@ const KeyboardAwareMixin = {
1314
this.setState({keyboardSpace: _KAM_DEFAULT_TAB_BAR_HEIGHT})
1415
},
1516

17+
setResetScrollToCoords: function (coords: {x: number, y: number}) {
18+
this.resetCoords = coords
19+
},
20+
1621
getInitialState: function (props: Object) {
1722
this.viewIsInsideTabBar = false
1823
this.keyboardWillShowEvent = undefined
@@ -28,13 +33,20 @@ const KeyboardAwareMixin = {
2833
this.setState({
2934
keyboardSpace: keyboardSpace,
3035
})
36+
// Automatically scroll to focused TextInput
37+
const currentlyFocusedField = TextInput.State.currentlyFocusedField()
38+
this.scrollToFocusedInputWithNodeHandle(currentlyFocusedField)
3139
},
3240

3341
resetKeyboardSpace: function () {
3442
const keyboardSpace = (this.props.viewIsInsideTabBar) ? _KAM_DEFAULT_TAB_BAR_HEIGHT : 0
3543
this.setState({
3644
keyboardSpace: keyboardSpace,
3745
})
46+
// Reset scroll position after keyboard dismissal
47+
if (this.resetCoords) {
48+
this.scrollToPosition(this.resetCoords.x, this.resetCoords.y, true)
49+
}
3850
},
3951

4052
componentDidMount: function () {
@@ -49,22 +61,25 @@ const KeyboardAwareMixin = {
4961
},
5062

5163
scrollToPosition: function (x: number, y: number, animated: bool = false) {
52-
const scrollView = this.refs.keyboardView.getScrollResponder()
53-
this.setTimeout(() => {
54-
scrollView.scrollResponderScrollTo({x: x, y: y, animated: animated});
55-
}, 220)
64+
const scrollView = this.refs._rnkasv_keyboardView.getScrollResponder()
65+
scrollView.scrollResponderScrollTo({x: x, y: y, animated: animated})
5666
},
5767

5868
/**
5969
* @param extraHeight: takes an extra height in consideration.
6070
*/
61-
scrollToFocusedInput: function (event: Object, reactNode: Object, extraHeight: number = _KAM_DEFAULT_TAB_BAR_HEIGHT) {
62-
const scrollView = this.refs.keyboardView.getScrollResponder()
71+
scrollToFocusedInput: function (reactNode: Object, extraHeight: number = _KAM_DEFAULT_TAB_BAR_HEIGHT) {
72+
const scrollView = this.refs._rnkasv_keyboardView.getScrollResponder()
6373
this.setTimeout(() => {
6474
scrollView.scrollResponderScrollNativeHandleToKeyboard(
6575
reactNode, extraHeight, true
6676
)
67-
}, 220)
77+
}, _KAM_KEYBOARD_OPENING_TIME)
78+
},
79+
80+
scrollToFocusedInputWithNodeHandle: function (nodeID: number, extraHeight: number = _KAM_DEFAULT_TAB_BAR_HEIGHT) {
81+
const reactNode = ReactNative.findNodeHandle(nodeID)
82+
this.scrollToFocusedInput(reactNode, extraHeight)
6883
},
6984
}
7085

lib/KeyboardAwareScrollView.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,22 @@ const KeyboardAwareScrollView = React.createClass({
88
propTypes: {
99
...ScrollView.propTypes,
1010
viewIsInsideTabBar: PropTypes.bool,
11+
resetScrollToCoords: PropTypes.shape({
12+
x: PropTypes.number,
13+
y: PropTypes.number,
14+
}),
1115
},
1216
mixins: [KeyboardAwareMixin],
1317

14-
componentWillMount: function() {
15-
if (this.props.viewIsInsideTabBar) {
16-
this.setViewIsInsideTabBar(this.props.viewIsInsideTabBar)
17-
}
18+
componentWillMount: function () {
19+
this.setViewIsInsideTabBar(this.props.viewIsInsideTabBar)
20+
this.setResetScrollToCoords(this.props.resetScrollToCoords)
1821
},
1922

2023
render: function () {
2124
return (
2225
<ScrollView
23-
ref='keyboardView'
26+
ref='_rnkasv_keyboardView'
2427
keyboardDismissMode='interactive'
2528
contentInset={{bottom: this.state.keyboardSpace}}
2629
showsVerticalScrollIndicator={true}

0 commit comments

Comments
 (0)