Skip to content

Commit 5ad78bc

Browse files
Merge pull request #147 from Swordsman-Inaction/android-support
Add Android Support
2 parents f4805f2 + dad0775 commit 5ad78bc

File tree

4 files changed

+97
-9
lines changed

4 files changed

+97
-9
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,28 @@ You can register to `ScrollViewResponder` events `onKeyboardWillShow` and `onKey
9191
</KeyboardAwareScrollView>
9292
```
9393
94+
## Android Support
95+
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).
96+
97+
But if you want to use feature like `extraHeight`, you need to enable Android Support with the following steps:
98+
99+
- Make sure you are using react-native `0.46` or above.
100+
- Set `windowSoftInputMode` to `adjustPan` in `AndroidManifest.xml`.
101+
- Set `enableOnAndroid` property to `true`.
102+
103+
Android Suppor is not perfect, here is the support list:
104+
105+
| **Prop** | **Android Support** |
106+
|----------|-----------------|
107+
| `viewIsInsideTabBar` | Yes |
108+
| `resetScrollToCoords` | Yes |
109+
| `enableAutoAutomaticScroll` | Yes |
110+
| `extraHeight` | Yes |
111+
| `extraScrollHeight` | Yes |
112+
| `enableResetScrollToCoords` | Yes |
113+
| `keyboardOpeningTime` | No |
114+
115+
94116
## API
95117
### Props
96118
All the `ScrollView`/`ListView` props will be passed.
@@ -104,6 +126,7 @@ All the `ScrollView`/`ListView` props will be passed.
104126
| `extraScrollHeight` | `number` | Adds an extra offset to the keyboard. Useful if you want to stick elements above the keyboard. |
105127
| `enableResetScrollToCoords` | `boolean` | Lets the user enable or disable automatic resetScrollToCoords. |
106128
| `keyboardOpeningTime` | `number` | Sets the delay time before scrolling to new position, default is 250 |
129+
| `enableOnAndroid` | `boolean` | Enable Android Support |
107130
108131
| **Method** | **Parameter** | **Description** |
109132
|------------|---------------|-----------------|

lib/KeyboardAwareListView.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import React from 'react'
44
import createReactClass from 'create-react-class'
5-
import { ListView } from 'react-native'
5+
import { ListView, Platform } from 'react-native'
66
import PropTypes from 'prop-types'
77
import KeyboardAwareMixin from './KeyboardAwareMixin'
88

@@ -14,6 +14,7 @@ const KeyboardAwareListView = createReactClass({
1414
y: PropTypes.number.isRequired,
1515
}),
1616
onScroll: PropTypes.func,
17+
enableOnAndroid: PropTypes.bool,
1718
},
1819
mixins: [KeyboardAwareMixin],
1920

@@ -30,15 +31,32 @@ const KeyboardAwareListView = createReactClass({
3031
},
3132

3233
render: function () {
34+
const {
35+
enableOnAndroid,
36+
contentContainerStyle,
37+
} = this.props
38+
39+
const {
40+
keyboardSpace,
41+
} = this.state
42+
43+
let newContentContainerStyle
44+
45+
if (Platform.OS === 'android' && enableOnAndroid) {
46+
newContentContainerStyle = Object.assign({}, contentContainerStyle)
47+
newContentContainerStyle.paddingBottom = (newContentContainerStyle.paddingBottom || 0) + keyboardSpace
48+
}
49+
3350
return (
3451
<ListView
3552
ref='_rnkasv_keyboardView'
3653
keyboardDismissMode='interactive'
37-
contentInset={{bottom: this.state.keyboardSpace}}
54+
contentInset={{bottom: keyboardSpace}}
3855
automaticallyAdjustContentInsets={false}
3956
showsVerticalScrollIndicator={true}
4057
scrollEventThrottle={0}
4158
{...this.props}
59+
contentContainerStyle={newContentContainerStyle || contentContainerStyle}
4260
onScroll={this.onScroll}
4361
/>
4462
)

lib/KeyboardAwareMixin.js

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* @flow */
22

33
import PropTypes from 'prop-types'
4-
import ReactNative, { TextInput, Keyboard, UIManager } from 'react-native'
4+
import ReactNative, { TextInput, Keyboard, UIManager, Platform } from 'react-native'
55
import TimerMixin from 'react-timer-mixin'
66

77
const _KAM_DEFAULT_TAB_BAR_HEIGHT: number = 49
@@ -70,8 +70,28 @@ const KeyboardAwareMixin = {
7070
if (isAncestor) {
7171
// Check if the TextInput will be hidden by the keyboard
7272
UIManager.measureInWindow(currentlyFocusedField, (x, y, width, height) => {
73-
if (y + height > frames.endCoordinates.screenY - this.props.extraScrollHeight - this.props.extraHeight) {
74-
this.scrollToFocusedInputWithNodeHandle(currentlyFocusedField)
73+
const textInputBottomPosition = y + height
74+
const keyboardPosition = frames.endCoordinates.screenY
75+
const totalExtraHeight = this.props.extraScrollHeight + this.props.extraHeight
76+
77+
if (Platform.OS === 'ios') {
78+
if (textInputBottomPosition > keyboardPosition - totalExtraHeight) {
79+
this.scrollToFocusedInputWithNodeHandle(currentlyFocusedField)
80+
}
81+
} else {
82+
83+
// on android, the system would scroll the text input just above the keyboard
84+
// so we just neet to scroll the extra height part
85+
if (textInputBottomPosition > keyboardPosition) {
86+
// since the system already scrolled the whole view up
87+
// we should reduce that amount
88+
keyboardSpace = keyboardSpace - (textInputBottomPosition - keyboardPosition)
89+
this.setState({keyboardSpace})
90+
91+
this.scrollForExtraHeightOnAndroid(totalExtraHeight)
92+
} else if (textInputBottomPosition > keyboardPosition - totalExtraHeight) {
93+
this.scrollForExtraHeightOnAndroid(totalExtraHeight - (keyboardPosition - textInputBottomPosition))
94+
}
7595
}
7696
})
7797
}
@@ -106,8 +126,13 @@ const KeyboardAwareMixin = {
106126

107127
componentDidMount: function () {
108128
// Keyboard events
109-
this.keyboardWillShowEvent = Keyboard.addListener('keyboardWillShow', this.updateKeyboardSpace)
110-
this.keyboardWillHideEvent = Keyboard.addListener('keyboardWillHide', this.resetKeyboardSpace)
129+
if (Platform.OS === 'ios') {
130+
this.keyboardWillShowEvent = Keyboard.addListener('keyboardWillShow', this.updateKeyboardSpace)
131+
this.keyboardWillHideEvent = Keyboard.addListener('keyboardWillHide', this.resetKeyboardSpace)
132+
} else if (Platform.OS === 'android' && this.props.enableOnAndroid) {
133+
this.keyboardWillShowEvent = Keyboard.addListener('keyboardDidShow', this.updateKeyboardSpace)
134+
this.keyboardWillHideEvent = Keyboard.addListener('keyboardDidHide', this.resetKeyboardSpace)
135+
}
111136
},
112137

113138
componentWillUnmount: function () {
@@ -129,6 +154,10 @@ const KeyboardAwareMixin = {
129154
responder && responder.scrollResponderScrollToEnd({animated: animated})
130155
},
131156

157+
scrollForExtraHeightOnAndroid(extraHeight: number) {
158+
this.scrollToPosition(0, this.position.y + extraHeight, true)
159+
},
160+
132161
/**
133162
* @param keyboardOpeningTime: takes a different keyboardOpeningTime in consideration.
134163
* @param extraHeight: takes an extra height in consideration.

lib/KeyboardAwareScrollView.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import React from 'react'
44
import createReactClass from 'create-react-class'
5-
import { ScrollView } from 'react-native'
5+
import { ScrollView, Platform } from 'react-native'
66
import PropTypes from 'prop-types'
77
import KeyboardAwareMixin from './KeyboardAwareMixin'
88

@@ -14,6 +14,7 @@ const KeyboardAwareScrollView = createReactClass({
1414
x: PropTypes.number,
1515
y: PropTypes.number,
1616
}),
17+
enableOnAndroid: PropTypes.bool,
1718
},
1819
mixins: [KeyboardAwareMixin],
1920

@@ -23,15 +24,32 @@ const KeyboardAwareScrollView = createReactClass({
2324
},
2425

2526
render: function () {
27+
const {
28+
enableOnAndroid,
29+
contentContainerStyle,
30+
} = this.props
31+
32+
const {
33+
keyboardSpace,
34+
} = this.state
35+
36+
let newContentContainerStyle
37+
38+
if (Platform.OS === 'android' && enableOnAndroid) {
39+
newContentContainerStyle = Object.assign({}, contentContainerStyle)
40+
newContentContainerStyle.paddingBottom = (newContentContainerStyle.paddingBottom || 0) + keyboardSpace
41+
}
42+
2643
return (
2744
<ScrollView
2845
ref='_rnkasv_keyboardView'
2946
keyboardDismissMode='interactive'
30-
contentInset={{bottom: this.state.keyboardSpace}}
47+
contentInset={{bottom: keyboardSpace}}
3148
automaticallyAdjustContentInsets={false}
3249
showsVerticalScrollIndicator={true}
3350
scrollEventThrottle={0}
3451
{...this.props}
52+
contentContainerStyle={newContentContainerStyle || contentContainerStyle}
3553
onScroll={e => {
3654
this.handleOnScroll(e)
3755
this.props.onScroll && this.props.onScroll(e)

0 commit comments

Comments
 (0)