Skip to content

Commit

Permalink
🎉 Adds support for auto TextInput onFocus scroll (#22)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
alvaromb committed May 31, 2016
1 parent ffedf32 commit c6211c4
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 27 deletions.
42 changes: 33 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# react-native-keyboard-aware-scroll-view
A ScrollView component that handles keyboard appearance.
A ScrollView component that handles keyboard appearance and automatically scrolls to focused `TextInput`.

<p align="center">
<img src="https://raw.githubusercontent.com/wiki/APSL/react-native-keyboard-aware-scroll-view/kasv.gif" alt="Scroll demo" width="400">
</p>

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

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

The component accepts the experimental prop ``viewIsInsideTabBar``, which tries
to solve resizing issues when rendering inside a ``TabBar`` component.

## Auto-scroll in `TextInput` fields
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:
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.

### Programatically scroll to any `TextInput`
In order to scroll to any `TextInput` field, you can use the built-in method `scrollToFocusedInput`. Example:

```js
_scrollToInput (event, reactNode) {
_scrollToInput (reactNode: any) {
// Add a 'scroll' ref to your ScrollView
this.refs.scroll.scrollToFocusedInput(event, reactNode)
this.refs.scroll.scrollToFocusedInput(reactNode)
}
```

```jsx
<KeyboardAwareScrollView ref='scroll'>
<View>
<TextInput ref='myInput' onFocus={this._scrollToInput}/>
<TextInput onFocus={(event: Event) => {
// `bind` the function if you're using ES6 classes
this._scrollToInput(ReactNative.findNodeHandle(event.target))
}/>
</View>
</KeyboardAwareScrollView>
```
### Programatically scroll to any position
There's another built-in function that lets you programatically scroll to any position of the scroll view:
```js
this.refs.scroll.scrollToPosition(0, 0, true)
```
## Register to keyboard events
You can register to `ScrollViewResponder` events `onKeyboardWillShow` and `onKeyboardWillHide`:
Expand All @@ -67,6 +81,16 @@ You can register to `ScrollViewResponder` events `onKeyboardWillShow` and `onKey
</KeyboardAwareScrollView>
```
## API
### Props
All the `ScrollView`/`ListView` props will be passed.
| **Prop** | **Type** | **Description** |
|----------|----------|-----------------|
| `viewIsInsideTabBar` | `boolean` | Adds an extra offset that represents the `TabBarIOS` height. |
| `resetScrollToCoords` | `Object: {x: number, y: number}` | Coordinates that will be used to reset the scroll when the keyboard hides. |
## License
MIT.
13 changes: 8 additions & 5 deletions lib/KeyboardAwareListView.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,22 @@ const KeyboardAwareListView = React.createClass({
propTypes: {
...ListView.propTypes,
viewIsInsideTabBar: React.PropTypes.bool,
resetScrollToCoords: PropTypes.shape({
x: PropTypes.number,
y: PropTypes.number,
}),
},
mixins: [KeyboardAwareMixin],

componentWillMount: function() {
if (this.props.viewIsInsideTabBar) {
this.setViewIsInsideTabBar(this.props.viewIsInsideTabBar)
}
componentWillMount: function () {
this.setViewIsInsideTabBar(this.props.viewIsInsideTabBar)
this.setResetScrollToCoords(this.props.resetScrollToCoords)
},

render: function () {
return (
<ListView
ref='keyboardView'
ref='_rnkasv_keyboardView'
keyboardDismissMode='interactive'
contentInset={{bottom: this.state.keyboardSpace}}
showsVerticalScrollIndicator={true}
Expand Down
31 changes: 23 additions & 8 deletions lib/KeyboardAwareMixin.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/* @flow */

import { DeviceEventEmitter } from 'react-native'
import ReactNative, { TextInput, DeviceEventEmitter } from 'react-native'
import TimerMixin from 'react-timer-mixin'

const _KAM_DEFAULT_TAB_BAR_HEIGHT = 49
const _KAM_KEYBOARD_OPENING_TIME = 250

const KeyboardAwareMixin = {
mixins: [TimerMixin],
Expand All @@ -13,6 +14,10 @@ const KeyboardAwareMixin = {
this.setState({keyboardSpace: _KAM_DEFAULT_TAB_BAR_HEIGHT})
},

setResetScrollToCoords: function (coords: {x: number, y: number}) {
this.resetCoords = coords
},

getInitialState: function (props: Object) {
this.viewIsInsideTabBar = false
this.keyboardWillShowEvent = undefined
Expand All @@ -28,13 +33,20 @@ const KeyboardAwareMixin = {
this.setState({
keyboardSpace: keyboardSpace,
})
// Automatically scroll to focused TextInput
const currentlyFocusedField = TextInput.State.currentlyFocusedField()
this.scrollToFocusedInputWithNodeHandle(currentlyFocusedField)
},

resetKeyboardSpace: function () {
const keyboardSpace = (this.props.viewIsInsideTabBar) ? _KAM_DEFAULT_TAB_BAR_HEIGHT : 0
this.setState({
keyboardSpace: keyboardSpace,
})
// Reset scroll position after keyboard dismissal
if (this.resetCoords) {
this.scrollToPosition(this.resetCoords.x, this.resetCoords.y, true)
}
},

componentDidMount: function () {
Expand All @@ -49,22 +61,25 @@ const KeyboardAwareMixin = {
},

scrollToPosition: function (x: number, y: number, animated: bool = false) {
const scrollView = this.refs.keyboardView.getScrollResponder()
this.setTimeout(() => {
scrollView.scrollResponderScrollTo({x: x, y: y, animated: animated});
}, 220)
const scrollView = this.refs._rnkasv_keyboardView.getScrollResponder()
scrollView.scrollResponderScrollTo({x: x, y: y, animated: animated})
},

/**
* @param extraHeight: takes an extra height in consideration.
*/
scrollToFocusedInput: function (event: Object, reactNode: Object, extraHeight: number = _KAM_DEFAULT_TAB_BAR_HEIGHT) {
const scrollView = this.refs.keyboardView.getScrollResponder()
scrollToFocusedInput: function (reactNode: Object, extraHeight: number = _KAM_DEFAULT_TAB_BAR_HEIGHT) {
const scrollView = this.refs._rnkasv_keyboardView.getScrollResponder()
this.setTimeout(() => {
scrollView.scrollResponderScrollNativeHandleToKeyboard(
reactNode, extraHeight, true
)
}, 220)
}, _KAM_KEYBOARD_OPENING_TIME)
},

scrollToFocusedInputWithNodeHandle: function (nodeID: number, extraHeight: number = _KAM_DEFAULT_TAB_BAR_HEIGHT) {
const reactNode = ReactNative.findNodeHandle(nodeID)
this.scrollToFocusedInput(reactNode, extraHeight)
},
}

Expand Down
13 changes: 8 additions & 5 deletions lib/KeyboardAwareScrollView.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,22 @@ const KeyboardAwareScrollView = React.createClass({
propTypes: {
...ScrollView.propTypes,
viewIsInsideTabBar: PropTypes.bool,
resetScrollToCoords: PropTypes.shape({
x: PropTypes.number,
y: PropTypes.number,
}),
},
mixins: [KeyboardAwareMixin],

componentWillMount: function() {
if (this.props.viewIsInsideTabBar) {
this.setViewIsInsideTabBar(this.props.viewIsInsideTabBar)
}
componentWillMount: function () {
this.setViewIsInsideTabBar(this.props.viewIsInsideTabBar)
this.setResetScrollToCoords(this.props.resetScrollToCoords)
},

render: function () {
return (
<ScrollView
ref='keyboardView'
ref='_rnkasv_keyboardView'
keyboardDismissMode='interactive'
contentInset={{bottom: this.state.keyboardSpace}}
showsVerticalScrollIndicator={true}
Expand Down

0 comments on commit c6211c4

Please sign in to comment.