React-native键盘遮挡输入框问题的解决
2017-03-05 16:43
495 查看
现在有一个更准确一点的做法是用一个View包裹住TextInput,然后通过该View的onLayout方法获取该输入框的y轴位置,再减去一个适当的高度去处理scrollview的滚动,如下所示:
RN中要解决键盘遮挡输入框的问题其实有挺多方式,在这里只是记录其中的一些个人实际开发中使用到的。
方式一、使用scrollTo方法,这也是最简单最粗暴的,只是需要计算scrollview滚动的距离,并且处理一些体验的bug问题。大致思路是:组件render方法中使用scrollview,并且设置scrollview的keyboardShouldPersistTaps={true}(此步一定不能少,如果缺少该属性,接下来的一步将会不起作用),然后在scrollview中用一个view作为container包裹所有剩余的子视图,比如Text,TouchableHighlight之类的,并且用onStartShouldSetResponderCapture截取该view的事件,用以解决当点击页面上的按钮时,第一次点击只会收起键盘,第二次点击才会响应按钮方法的bug。然后在TextInput的onFocus方法中滚动scrollview,在onEndEditing中恢复scrollview的滚动。以下是在具体实现中的代码。
render方法的实现:
render:function() {
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'
/>
<View style = {styles.lineView}></View>
<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>
<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);
},
方式二、使用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的值即可.
方式三、通过监听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>
<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中要解决键盘遮挡输入框的问题其实有挺多方式,在这里只是记录其中的一些个人实际开发中使用到的。
方式一、使用scrollTo方法,这也是最简单最粗暴的,只是需要计算scrollview滚动的距离,并且处理一些体验的bug问题。大致思路是:组件render方法中使用scrollview,并且设置scrollview的keyboardShouldPersistTaps={true}(此步一定不能少,如果缺少该属性,接下来的一步将会不起作用),然后在scrollview中用一个view作为container包裹所有剩余的子视图,比如Text,TouchableHighlight之类的,并且用onStartShouldSetResponderCapture截取该view的事件,用以解决当点击页面上的按钮时,第一次点击只会收起键盘,第二次点击才会响应按钮方法的bug。然后在TextInput的onFocus方法中滚动scrollview,在onEndEditing中恢复scrollview的滚动。以下是在具体实现中的代码。
render方法的实现:
render:function() {
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'
/>
<View style = {styles.lineView}></View>
<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>
<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);
},
方式二、使用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的值即可.
方式三、通过监听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>
相关文章推荐
- React-Native解决键盘遮挡问题(Keyboard遮挡问题)
- React Native 解决ScrollView 上 TextInput 键盘遮挡问题
- 详解React-Native解决键盘遮挡问题(Keyboard遮挡问题)
- react在安卓中输入框被手机键盘遮挡问题的解决方法
- React-Native解决键盘遮挡问题(Keyboard遮挡问题)
- React Native TextInput键盘遮挡输入款问题
- Android WebView 全屏下 输入框被键盘遮挡 问题解决
- Android WebView 软键盘遮挡输入框问题的解决方法
- 《React-Native系列》42、键盘遮挡问题官方处理方法KeyboardAvoidingView
- ReactNative键盘遮挡TextInput解决
- 如何解决键盘遮挡输入框问题
- 解决键盘遮挡输入框(UITextField)问题
- 弹出键盘时遮挡输入框的问题解决
- iOS项目开发键盘弹出遮挡输入框问题解决方案
- IOS学习笔记36—解决键盘遮挡输入框(UITextField)问题
- React Native 键盘管理和 Tab Navigator 在Android TextInput遮盖,Tab Navigator上移等问题解决办法
- iOS解决键盘弹出遮挡输入框问题
- 解决react-native软键盘弹出挡住输入框的问题
- 简单完美的解决键盘遮挡输入框的问题
- 一招解决全局键盘遮挡输入框问题