2016年10月25日更新:react
如今有一個更準確一點的作法是用一個View包裹住TextInput,而後經過該View的onLayout方法獲取該輸入框的y軸位置,再減去一個適當的高度去處理scrollview的滾動,以下所示:git
<View onLayout={this._downloadLayout.bind(this)}
style={{marginLeft:15,flexDirection: 'column',alignItems:'flex-start'}}>
<TextInput
style={styles.inputStyle}
defaultValue={this.state.downloadUrl}
placeholder = '輸入下載地址'
ref = 'downloadInput'
onFocus = {this._downLoadFocus.bind(this)}
onChangeText={(text) => this.setState({downloadUrl:text})}
/>
</View>
而後實現_downloadLayout方法:
_downloadLayout(e){
this.setState({
downloadY:e.nativeEvent.layout.y,
});
}
以後再實現TextInput的onFocus方法,對包裹的整個scrollview頁面進行滾動:
_downLoadFocus(){
let scroller = this.refs.scroller;
iOS&& setTimeout(()=>{
let y = this.state.downloadY - 1/3*Dev_height;//Dev_height爲屏幕的高度
scroller&&scroller.scrollTo({x:0, y:y, animated:true});
},50);
}
這樣的處理適合大多數的狀況。
評論裏有小夥伴說React.findNodeHandle已經不可使用了,應該是使用了rn更新的版本,因此咱們在使用的時也須要根據版本的不一樣去選擇合適的方法,
感謝他的提醒,新版本可使用下面這個方法
import ReactNative from 'react-native';
...
ReactNative.findNodeHandle(...)
RN中要解決鍵盤遮擋輸入框的問題其實有挺多方式,在這裏只是記錄其中的一些我的實際開發中使用到的。github
方式1、使用scrollTo方法,這也是最簡單最粗暴的,只是須要計算scrollview滾動的距離,而且處理一些體驗的bug問題。大體思路是:組件render方法中使用scrollview,而且設置scrollview的keyboardShouldPersistTaps={true}(此步必定不能少,若是缺乏該屬性,接下來的一步將會不起做用),而後在scrollview中用一個view做爲container包裹全部剩餘的子視圖,好比Text,TouchableHighlight之類的,而且用onStartShouldSetResponderCapture截取該view的事件,用以解決當點擊頁面上的按鈕時,第一次點擊只會收起鍵盤,第二次點擊纔會響應按鈕方法的bug。而後在TextInput的onFocus方法中滾動scrollview,在onEndEditing中恢復scrollview的滾動。如下是在具體實現中的代碼。react-native
render方法的實現:ide
render:function() {flex
return(
<View style={styles.container}>
<NavigationBar title={'綁定手機號'} onBackPress={this.onBackPress}/>
<ScrollView ref='scroll' keyboardShouldPersistTaps={true} >
<View style={styles.content} onStartShouldSetResponderCapture={(e) => {
const target = e.nativeEvent.target;
if (target !== React.findNodeHandle(this.refs.phoneInput) && target !== React.findNodeHandle(this.refs.codeInput)) {
this.refs.phoneInput.blur();
this.refs.codeInput.blur();
}}}>動畫
<TextInput
style = {styles.cardNumText}
ref = 'phoneInput'
onFocus={this.scrollViewTo.bind(this)}
onEndEditing={()=>{this.refs.scroll.scrollTo(0)}}
onChange = {this.cardNumberTextChanged.bind(this)}
placeholder = '請輸入預留手機號'
placeholderTextColor = '#481A5C'
keyboardType = 'numeric'
/>this
<View style = {styles.lineView}></View>spa
<TouchableHighlight style = {styles.topButton} underlayColor='#9B9B9B' onPress = {this.jumpToNextPage.bind(this)}>
<Text style = {styles.buttonText}>發送驗證碼</Text>
</TouchableHighlight>
<TextInput
style = {styles.cardNumText}
ref = 'codeInput'
onFocus={this.scrollViewTo.bind(this)}
onEndEditing={()=>{this.refs.scroll.scrollTo(0)}}
placeholder = '輸入驗證碼'
placeholderTextColor = '#999'
onChange = {this.cardNumberTextChanged}
keyboardType = 'number-pad'
/>
<View style = {styles.lineView}></View>code
<Text style = {styles.protectText}>
XXXXXXXXXXXXXXXXXXX
</Text>
<TouchableHighlight style = {styles.downButton} underlayColor='#481A5C' onPress = {this.jumpToNextPage.bind(this)}>
<Text style = {styles.buttonText}>下一步</Text>
</TouchableHighlight>
</View>
</ScrollView>
</View>);
}
onFocus時調用的scrollViewTo方法的實現:
scrollViewTo:function(e){
let target = e.nativeEvent.target;
let scrollLength = 100;
if (target=== React.findNodeHandle(this.refs.codeInput)) {
scrollLength = 160;
}
this.refs.scroll.scrollTo(scrollLength);
},
方式2、使用View包裹時,經過設置View的marginTop屬性而且結合動畫來實現:初始化一個state對象的值viewMarginTop用於設置Animated.View的marginTop,在textInput的onfocus時改變viewMarginTop的值,在onEndediting時恢復或者設置新的marginTop。具體爲首先引入Animated,而且初始化state方法。(state內值的變化會觸發界面上相關元素的再次薰染,具備reactivecocoa的相同的做用)
getInitialState: function () {
return {
viewMarginTop: new Animated.Value(0),
};
},
在須要上升的視圖中使用Animated.View,設置其mairginTop爲viewMarginTop
<Animated.View style={{marginTop:this.state.viewMarginTop}}>
//固然不建議將樣式寫在這裏,這樣會致使每次薰染都建立一次樣式,你應該將樣式定義到StyleSheet中
//your Views and component
</Animated.View>
而後在onFucos的方法中用動畫改變viewMarginTop的值,以下
Animated.timing(
this.state.viewMarginTop,
{
toValue: 160,
duration: 250,
}
).start();
要恢復只須要在onEndediting中用一樣的原理恢復viewMarginTop的值便可.
方式3、經過監聽scrollview上鍵盤的出現和消失,在出現和消失方法中設置某個state值的變化,來設置scrollview的contentInset,該方法只是在github上看過,具體本人並無用過即:
1.在頁面薰染完時添加監聽
componentDidMount: function () {
// Keyboard events監聽
DeviceEventEmitter.addListener('keyboardWillShow', this.updateKeyboardSpace)
DeviceEventEmitter.addListener('keyboardWillHide', this.resetKeyboardSpace)
},
componentWillUnmount: function () {
// TODO: figure out if removeAllListeners is the right thing to do
DeviceEventEmitter.removeAllListeners('keyboardWillShow')
DeviceEventEmitter.removeAllListeners('keyboardWillHide')
},
getInitialState: function (props) {//初始化變量
this.viewIsInsideTabBar = false
return {
keyboardSpace: 0,
}
},
// Keyboard actions
updateKeyboardSpace: function (frames) {
const keyboardSpace = frames.endCoordinates.height//獲取鍵盤高度
this.setState({
keyboardSpace: keyboardSpace,
})
},
resetKeyboardSpace: function () {
this.setState({
keyboardSpace: 0,
})
},
//設置scrollview的contentInset
<ScrollView ref='keyboardView' keyboardDismissMode='interactive' contentInset={{bottom: this.state.keyboardSpace}} showsVerticalScrollIndicator={true} </ScrollView>