diff --git a/README.md b/README.md index ea3884e..efc1ca1 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,28 @@ You can register to `ScrollViewResponder` events `onKeyboardWillShow` and `onKey ``` +## Android Support +First, Android natively has this feature, you can easily enable it by setting `windowSoftInputMode` in `AndroidManifest.xml`. Check [here](https://developer.android.com/guide/topics/manifest/activity-element.html#wsoft). + +But if you want to use feature like `extraHeight`, you need to enable Android Support with the following steps: + +- Make sure you are using react-native `0.46` or above. +- Set `windowSoftInputMode` to `adjustPan` in `AndroidManifest.xml`. +- Set `enableOnAndroid` property to `true`. + +Android Suppor is not perfect, here is the support list: + +| **Prop** | **Android Support** | +|----------|-----------------| +| `viewIsInsideTabBar` | Yes | +| `resetScrollToCoords` | Yes | +| `enableAutoAutomaticScroll` | Yes | +| `extraHeight` | Yes | +| `extraScrollHeight` | Yes | +| `enableResetScrollToCoords` | Yes | +| `keyboardOpeningTime` | No | + + ## API ### Props All the `ScrollView`/`ListView` props will be passed. @@ -104,6 +126,7 @@ All the `ScrollView`/`ListView` props will be passed. | `extraScrollHeight` | `number` | Adds an extra offset to the keyboard. Useful if you want to stick elements above the keyboard. | | `enableResetScrollToCoords` | `boolean` | Lets the user enable or disable automatic resetScrollToCoords. | | `keyboardOpeningTime` | `number` | Sets the delay time before scrolling to new position, default is 250 | +| `enableOnAndroid` | `boolean` | Enable Android Support | | **Method** | **Parameter** | **Description** | |------------|---------------|-----------------| diff --git a/lib/KeyboardAwareListView.js b/lib/KeyboardAwareListView.js index 961d13c..ade8b5a 100644 --- a/lib/KeyboardAwareListView.js +++ b/lib/KeyboardAwareListView.js @@ -2,7 +2,7 @@ import React from 'react' import createReactClass from 'create-react-class' -import { ListView } from 'react-native' +import { ListView, Platform } from 'react-native' import PropTypes from 'prop-types' import KeyboardAwareMixin from './KeyboardAwareMixin' @@ -14,6 +14,7 @@ const KeyboardAwareListView = createReactClass({ y: PropTypes.number.isRequired, }), onScroll: PropTypes.func, + enableOnAndroid: PropTypes.bool, }, mixins: [KeyboardAwareMixin], @@ -30,15 +31,32 @@ const KeyboardAwareListView = createReactClass({ }, render: function () { + const { + enableOnAndroid, + contentContainerStyle, + } = this.props + + const { + keyboardSpace, + } = this.state + + let newContentContainerStyle + + if (Platform.OS === 'android' && enableOnAndroid) { + newContentContainerStyle = Object.assign({}, contentContainerStyle) + newContentContainerStyle.paddingBottom = (newContentContainerStyle.paddingBottom || 0) + keyboardSpace + } + return ( ) diff --git a/lib/KeyboardAwareMixin.js b/lib/KeyboardAwareMixin.js index a939196..467dc7c 100644 --- a/lib/KeyboardAwareMixin.js +++ b/lib/KeyboardAwareMixin.js @@ -1,7 +1,7 @@ /* @flow */ import PropTypes from 'prop-types' -import ReactNative, { TextInput, Keyboard, UIManager } from 'react-native' +import ReactNative, { TextInput, Keyboard, UIManager, Platform } from 'react-native' import TimerMixin from 'react-timer-mixin' const _KAM_DEFAULT_TAB_BAR_HEIGHT: number = 49 @@ -70,8 +70,28 @@ const KeyboardAwareMixin = { if (isAncestor) { // Check if the TextInput will be hidden by the keyboard UIManager.measureInWindow(currentlyFocusedField, (x, y, width, height) => { - if (y + height > frames.endCoordinates.screenY - this.props.extraScrollHeight - this.props.extraHeight) { - this.scrollToFocusedInputWithNodeHandle(currentlyFocusedField) + const textInputBottomPosition = y + height + const keyboardPosition = frames.endCoordinates.screenY + const totalExtraHeight = this.props.extraScrollHeight + this.props.extraHeight + + if (Platform.OS === 'ios') { + if (textInputBottomPosition > keyboardPosition - totalExtraHeight) { + this.scrollToFocusedInputWithNodeHandle(currentlyFocusedField) + } + } else { + + // on android, the system would scroll the text input just above the keyboard + // so we just neet to scroll the extra height part + if (textInputBottomPosition > keyboardPosition) { + // since the system already scrolled the whole view up + // we should reduce that amount + keyboardSpace = keyboardSpace - (textInputBottomPosition - keyboardPosition) + this.setState({keyboardSpace}) + + this.scrollForExtraHeightOnAndroid(totalExtraHeight) + } else if (textInputBottomPosition > keyboardPosition - totalExtraHeight) { + this.scrollForExtraHeightOnAndroid(totalExtraHeight - (keyboardPosition - textInputBottomPosition)) + } } }) } @@ -106,8 +126,13 @@ const KeyboardAwareMixin = { componentDidMount: function () { // Keyboard events - this.keyboardWillShowEvent = Keyboard.addListener('keyboardWillShow', this.updateKeyboardSpace) - this.keyboardWillHideEvent = Keyboard.addListener('keyboardWillHide', this.resetKeyboardSpace) + if (Platform.OS === 'ios') { + this.keyboardWillShowEvent = Keyboard.addListener('keyboardWillShow', this.updateKeyboardSpace) + this.keyboardWillHideEvent = Keyboard.addListener('keyboardWillHide', this.resetKeyboardSpace) + } else if (Platform.OS === 'android' && this.props.enableOnAndroid) { + this.keyboardWillShowEvent = Keyboard.addListener('keyboardDidShow', this.updateKeyboardSpace) + this.keyboardWillHideEvent = Keyboard.addListener('keyboardDidHide', this.resetKeyboardSpace) + } }, componentWillUnmount: function () { @@ -129,6 +154,10 @@ const KeyboardAwareMixin = { responder && responder.scrollResponderScrollToEnd({animated: animated}) }, + scrollForExtraHeightOnAndroid(extraHeight: number) { + this.scrollToPosition(0, this.position.y + extraHeight, true) + }, + /** * @param keyboardOpeningTime: takes a different keyboardOpeningTime in consideration. * @param extraHeight: takes an extra height in consideration. diff --git a/lib/KeyboardAwareScrollView.js b/lib/KeyboardAwareScrollView.js index c26c017..2897975 100644 --- a/lib/KeyboardAwareScrollView.js +++ b/lib/KeyboardAwareScrollView.js @@ -2,7 +2,7 @@ import React from 'react' import createReactClass from 'create-react-class' -import { ScrollView } from 'react-native' +import { ScrollView, Platform } from 'react-native' import PropTypes from 'prop-types' import KeyboardAwareMixin from './KeyboardAwareMixin' @@ -14,6 +14,7 @@ const KeyboardAwareScrollView = createReactClass({ x: PropTypes.number, y: PropTypes.number, }), + enableOnAndroid: PropTypes.bool, }, mixins: [KeyboardAwareMixin], @@ -23,15 +24,32 @@ const KeyboardAwareScrollView = createReactClass({ }, render: function () { + const { + enableOnAndroid, + contentContainerStyle, + } = this.props + + const { + keyboardSpace, + } = this.state + + let newContentContainerStyle + + if (Platform.OS === 'android' && enableOnAndroid) { + newContentContainerStyle = Object.assign({}, contentContainerStyle) + newContentContainerStyle.paddingBottom = (newContentContainerStyle.paddingBottom || 0) + keyboardSpace + } + return ( { this.handleOnScroll(e) this.props.onScroll && this.props.onScroll(e)