Skip to content

Commit 24bc79f

Browse files
committed
Merge branch 'master' into flat-list
2 parents b141aeb + 5ad78bc commit 24bc79f

File tree

7 files changed

+127
-28
lines changed

7 files changed

+127
-28
lines changed

.eslintrc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@
1414
},
1515

1616
"plugins": [
17-
"react"
17+
"react",
18+
"flowtype"
19+
],
20+
21+
"extends": [
22+
"plugin:flowtype/recommended"
1823
],
1924

2025
"globals": {

.flowconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-3]\\|1[0-9]\\|[0-9
9393
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
9494

9595
[version]
96-
0.33.0
96+
0.47.0

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: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,62 @@
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

99
const KeyboardAwareListView = createReactClass({
1010
propTypes: {
1111
viewIsInsideTabBar: PropTypes.bool,
1212
resetScrollToCoords: PropTypes.shape({
13-
x: PropTypes.number,
14-
y: PropTypes.number,
13+
x: PropTypes.number.isRequired,
14+
y: PropTypes.number.isRequired,
1515
}),
16+
onScroll: PropTypes.func,
17+
enableOnAndroid: PropTypes.bool,
1618
},
1719
mixins: [KeyboardAwareMixin],
1820

1921
componentWillMount: function () {
20-
this.setViewIsInsideTabBar(this.props.viewIsInsideTabBar)
21-
this.setResetScrollToCoords(this.props.resetScrollToCoords)
22+
this.setViewIsInsideTabBar(!!this.props.viewIsInsideTabBar)
23+
if (this.props.resetScrollToCoords) {
24+
this.setResetScrollToCoords(this.props.resetScrollToCoords)
25+
}
26+
},
27+
28+
onScroll: function (e: SyntheticEvent & {nativeEvent: {contentOffset: number}}) {
29+
this.handleOnScroll(e)
30+
this.props.onScroll && this.props.onScroll(e)
2231
},
2332

2433
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+
2550
return (
2651
<ListView
2752
ref='_rnkasv_keyboardView'
2853
keyboardDismissMode='interactive'
29-
contentInset={{bottom: this.state.keyboardSpace}}
54+
contentInset={{bottom: keyboardSpace}}
55+
automaticallyAdjustContentInsets={false}
3056
showsVerticalScrollIndicator={true}
3157
scrollEventThrottle={0}
3258
{...this.props}
33-
onScroll={e => {
34-
this.handleOnScroll(e)
35-
this.props.onScroll && this.props.onScroll(e)
36-
}}
59+
contentContainerStyle={newContentContainerStyle || contentContainerStyle}
60+
onScroll={this.onScroll}
3761
/>
3862
)
3963
},

lib/KeyboardAwareMixin.js

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
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

7-
import type { Event } from 'react-native'
8-
97
const _KAM_DEFAULT_TAB_BAR_HEIGHT: number = 49
108
const _KAM_KEYBOARD_OPENING_TIME: number = 250
119
const _KAM_EXTRA_HEIGHT: number = 75
@@ -30,7 +28,7 @@ const KeyboardAwareMixin = {
3028
}
3129
},
3230

33-
setViewIsInsideTabBar: function (viewIsInsideTabBar: bool) {
31+
setViewIsInsideTabBar: function (viewIsInsideTabBar: boolean) {
3432
this.viewIsInsideTabBar = viewIsInsideTabBar
3533
const keyboardSpace = viewIsInsideTabBar ? _KAM_DEFAULT_TAB_BAR_HEIGHT : 0
3634
if (this.state.keyboardSpace !== keyboardSpace) {
@@ -42,7 +40,7 @@ const KeyboardAwareMixin = {
4240
this.resetCoords = coords
4341
},
4442

45-
getInitialState: function (props: Object) {
43+
getInitialState: function () {
4644
this.viewIsInsideTabBar = false
4745
this.keyboardWillShowEvent = undefined
4846
this.keyboardWillHideEvent = undefined
@@ -72,8 +70,28 @@ const KeyboardAwareMixin = {
7270
if (isAncestor) {
7371
// Check if the TextInput will be hidden by the keyboard
7472
UIManager.measureInWindow(currentlyFocusedField, (x, y, width, height) => {
75-
if (y + height > frames.endCoordinates.screenY - this.props.extraScrollHeight - this.props.extraHeight) {
76-
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+
}
7795
}
7896
})
7997
}
@@ -108,8 +126,13 @@ const KeyboardAwareMixin = {
108126

109127
componentDidMount: function () {
110128
// Keyboard events
111-
this.keyboardWillShowEvent = Keyboard.addListener('keyboardWillShow', this.updateKeyboardSpace)
112-
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+
}
113136
},
114137

115138
componentWillUnmount: function () {
@@ -121,16 +144,20 @@ const KeyboardAwareMixin = {
121144
return this.refs._rnkasv_keyboardView && this.refs._rnkasv_keyboardView.getScrollResponder()
122145
},
123146

124-
scrollToPosition: function (x: number, y: number, animated: bool = true) {
147+
scrollToPosition: function (x: number, y: number, animated: boolean = true) {
125148
const responder = this.getScrollResponder();
126149
responder && responder.scrollResponderScrollTo({x: x, y: y, animated: animated})
127150
},
128151

129-
scrollToEnd: function (animated?: bool = true) {
152+
scrollToEnd: function (animated?: boolean = true) {
130153
const responder = this.getScrollResponder();
131154
responder && responder.scrollResponderScrollToEnd({animated: animated})
132155
},
133156

157+
scrollForExtraHeightOnAndroid(extraHeight: number) {
158+
this.scrollToPosition(0, this.position.y + extraHeight, true)
159+
},
160+
134161
/**
135162
* @param keyboardOpeningTime: takes a different keyboardOpeningTime in consideration.
136163
* @param extraHeight: takes an extra height in consideration.
@@ -169,7 +196,7 @@ const KeyboardAwareMixin = {
169196

170197
defaultResetScrollToCoords: null, // format: {x: 0, y: 0}
171198

172-
handleOnScroll: function (e: Event) {
199+
handleOnScroll: function (e: SyntheticEvent & {nativeEvent: {contentOffset: number}}) {
173200
this.position = e.nativeEvent.contentOffset
174201
},
175202
}

lib/KeyboardAwareScrollView.js

Lines changed: 21 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,14 +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}}
48+
automaticallyAdjustContentInsets={false}
3149
showsVerticalScrollIndicator={true}
3250
scrollEventThrottle={0}
3351
{...this.props}
52+
contentContainerStyle={newContentContainerStyle || contentContainerStyle}
3453
onScroll={e => {
3554
this.handleOnScroll(e)
3655
this.props.onScroll && this.props.onScroll(e)

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
"devDependencies": {
4444
"babel-eslint": "^6.0.4",
4545
"eslint": "^3.17.1",
46-
"eslint-plugin-react": "^6.10.0",
47-
"flow-bin": "0.33.0"
46+
"eslint-plugin-flowtype": "^2.35.0",
47+
"eslint-plugin-react": "^7.1.0",
48+
"flow-bin": "0.47.0"
4849
}
4950
}

0 commit comments

Comments
 (0)