目录
1.KeyboardAvoidingView
2.react-native-keyboard-aware-scroll-view
3.Keyboard Module
4.QQ聊天示例
4.1实现类似QQ聊天效果,点击输入框以后可以继续停留在未弹出键盘的位置;
4.2键盘显示或隐藏总是滚到底部
键盘遮挡
在开发中难免会用于(TextInput)输入框,可能会遇到键盘遮挡TextInput的情况,效果图:
示例代码:
render(){
return (<View style={styles.container}>
<Text style={{height:150,textAlignVertical:'center'}}>键盘遮挡</Text>
<TextInput ref="username1"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号1'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username2"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号2'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username3"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号3'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username4"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号4'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username5"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号5'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username6"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号6'}//提示语
style={styles.textInputStyle}
/>
</View>);
}
}
let styles = StyleSheet.create({
container:{
flex: 1,
justifyContent: 'center',
alignItems:'center',
backgroundColor:'#0ff'
},
textInputStyle:{height:50, width:'90%',backgroundColor:'#fff',marginTop:10, borderRadius:10}
});
介绍几种解决键盘遮挡问题的方法
1.KeyboardAvoidingView
本组件用于解决一个常见的尴尬问题:手机上弹出的键盘常常会挡住当前的视图。本组件可以自动根据键盘的位置,调整自身的 height 或底部的 padding,以避免被遮挡。
用法:
import { KeyboardAvoidingView } from 'react-native';
<KeyboardAvoidingView style={styles.container} behavior="padding" enabled>
... 在这里放置需要根据键盘调整位置的组件 ...
</KeyboardAvoidingView>
关键参数说明:
behavior:参数表示怎样显示键盘;
注意:Android 和 iOS 在此属性上表现并不一致。 Android 可能不指定此属性更好,而 iOS 可能相反。
通过测试behavior设置为padding基本满足需求的;
我们可以看到通过KeyboardAvoidingView包裹输入框以后基本可以满足需要了;
render(){
return (<KeyboardAvoidingView style={styles.container}
behavior= 'padding'>
<Text style={{height:150,textAlignVertical:'center'}}>键盘遮挡</Text>
<TextInput ref="username1"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号1'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username2"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号2'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username3"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号3'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username4"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号4'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username5"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号5'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username6"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号6'}//提示语
style={[styles.textInputStyle, {marginBottom:50}]}
/>
<Text style={[styles.textInputStyle, {textAlign:'center', textAlignVertical:'center'}]}>登录</Text>
</KeyboardAvoidingView>);
}
通过效果图我们会发现一个问题,视图是被直接顶上去了,显示在视图之外,界面无法滚动;
针对 Android 开发者:我发现这种方法是处理这个问题最好,也是唯一的办法。在 AndroidManifest.xml
中添加 android:windowSoftInputMode="adjustResize"。操作系统将为你解决大部分的问题,
KeyboardAvoidingView 会为你解决剩下的问题。参见https://gist.github.com/spencercarli/e1b9575c1c8845c2c20b86415dfba3db#file-
androidmanifest-xml-L23这个。
2.react-native-keyboard-aware-scroll-view
一个ScrollView组件,用于处理键盘外观并自动滚动到焦点文本输入。
您可以使用KeyboardAwareScrollView、KeyboardAwareSectionList或KeyboardAwareFlatList组件。它们分别继承Scrollview、SectionList和FlatList默认属性,并实现一个名为KeyboardAwareHOC的自定义高阶组件来处理键盘外观。如果要在任何其他组件中使用高阶组件,也可以使用它。
可以实现输入框获取焦点自动滚动到输入框的位置 ;
安装:
<KeyboardAwareScrollView>
<View>
<TextInput />
</View>
</KeyboardAwareScrollView>
npm i react-native-keyboard-aware-scroll-view --save
或
yarn add react-native-keyboard-aware-scroll-view
使用示例:
render(){
return (
<KeyboardAwareScrollView
innerRef={ref => {
this.scroll = ref //内部引用
}}
enableOnAndroid={true}
// contentContainerStyle={} //咱不定义此参数,会导致无法滚动
style={{ backgroundColor: '#4c69a5', flex:1}}
>
<View style={styles.container}>
<Text style={{height:150,textAlignVertical:'center'}}>键盘遮挡</Text>
<TextInput ref="username1"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号1'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username2"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号2'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username3"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号3'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username4"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号4'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username5"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号5'}//提示语
style={styles.textInputStyle}
/>
<TextInput ref="username6"
autoCapitalize='none' //设置首字母不自动大写
placeholder={'请输入账号6'}//提示语
style={[styles.textInputStyle, {marginBottom:50}]}
onFocus={(event: Event) => {
// `bind` the function if you're using ES6 classes
//获取焦点监听 this._scrollToInput(ReactNative.findNodeHandle(event.target))
}}
/>
<Text style={[styles.textInputStyle, {textAlign:'center', textAlignVertical:'center'}]}>登录</Text>
</View>
</KeyboardAwareScrollView>);
}
//滚动到获取焦点的输入框的位置
_scrollToInput (reactNode: any) {
// Add a 'scroll' ref to your ScrollView
this.scroll.props.scrollToFocusedInput(reactNode)
}
效果
注意事项:
Android加入android:windowSoftInputMode="adjustResize"
<activity
android:name=".MainActivity"
android:windowSoftInputMode="adjustResize"
>
KeyboardAwareScrollView:组件配置contentContainerStyle属性,会导致无法滚动;
更多功能支持可以参考官方git:https://github.com/APSL/react-native-keyboard-aware-scroll-view
可以监听键盘显示,滚动到任意位置等更多功能;
3.Keyboard Module
通过监听键盘显示和隐藏,用动画实现平滑滚动;
a.监听键盘显示和隐藏事件
componentWillMount() {
this.keyboardWillShowSub = Keyboard.addListener('keyboardDidShow', this.keyboardWillShow);
this.keyboardWWillHideSub = Keyboard.addListener('keyboardDidHide', this.keyboardWillHide);
}
b.执行相关动画
修改外层视图底部paddingBottom,绑定paddingBottom动画
paddingBottom: this.keyboardHeight
修改大图高度和宽度,绑定高度和宽度动画
style={[styles.logo, { height: this.imageHeight,width: this.imageWidth }]}
keyboardWillShow = (event) => {
Animated.parallel([Animated.timing(this.keyboardHeight, {
duration:100,//event.duration,
toValue:event.endCoordinates.height
}),
Animated.timing(this.imageHeight,{
duration:100,//event.duration,
toValue:50
}),
Animated.timing(this.imageWidth,{
duration:100,//event.duration,
toValue:50
})
]).start();
}
keyboardWillHide = (event) => {
// Alert.alert(this.imageHeight._value+
// '');
Animated.parallel([Animated.timing(this.keyboardHeight, {
duration:100,//event.duration,
toValue:0
}),
Animated.timing(this.imageHeight,{
duration:100,//event.duration,
toValue:300
}),
Animated.timing(this.imageWidth,{
duration:100,//event.duration,
toValue:300
})
]).start();
}
完整示例代码
import React, {Component} from 'react'
import ReactNative,{StyleSheet, TextInput, Animated, Keyboard} from 'react-native';
export default class TabTwo extends Component{
constructor(props){
super(props);
//定义动画
this.keyboardHeight = new Animated.Value(0);
this.imageHeight = new Animated.Value(300);
this.imageWidth = new Animated.Value(300);
}
componentWillUnmount() {
this.keyboardDidShowSub.remove();
this.keyboardDidHideSub.remove();
}
componentWillMount() {
//监听键盘显示和隐藏
this.keyboardDidShowSub = Keyboard.addListener('keyboardDidShow', this.keyboardDidShow);
this.keyboardDidHideSub = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide);
// //监听键盘弹出事件
// this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow',
// this.keyboardDidShowHandler.bind(this));
// //监听键盘隐藏事件
// this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide',
// this.keyboardDidHideHandler.bind(this));
}
//键盘显示
keyboardDidShow = (event) => {
//并行执行动画
Animated.parallel([Animated.timing(this.keyboardHeight, {
duration:100,//event.duration,
toValue:event.endCoordinates.height
}),
Animated.timing(this.imageHeight,{
duration:100,//event.duration,
toValue:50
}),
Animated.timing(this.imageWidth,{
duration:100,//event.duration,
toValue:50
})
]).start();
}
//键盘隐藏
keyboardDidHide = (event) => {
//并行执行动画
Animated.parallel([Animated.timing(this.keyboardHeight, {
duration:100,//event.duration,
toValue:0
}),
Animated.timing(this.imageHeight,{
duration:100,//event.duration,
toValue:300
}),
Animated.timing(this.imageWidth,{
duration:100,//event.duration,
toValue:300
})
]).start();
}
render(){
return (<Animated.View style={[styles.container, { paddingBottom: this.keyboardHeight }]}>
<Animated.Image source={require('./image/head.png')} style={[styles.logo, { height: this.imageHeight,width: this.imageWidth }]} />
<TextInput
placeholder="Email"
style={styles.input}
/>
<TextInput
placeholder="Username"
style={styles.input}
/>
<TextInput
placeholder="Password"
style={styles.input}
/>
<TextInput
placeholder="Confirm Password"
style={styles.input}
/>
</Animated.View>
);
}
// _scrollToInput (reactNode: any) {
// // Add a 'scroll' ref to your ScrollView
// this.scroll.props.scrollToFocusedInput(reactNode)
// }
}
let styles = StyleSheet.create({
container:{
flex: 1,
justifyContent: 'center',
alignItems:'center',
backgroundColor:'#0ff',
},
textInputStyle:{height:70, width:'90%',backgroundColor:'#fff',marginTop:10, borderRadius:10},
contentContainer: {
flex: 1
}
});
最外层的paddingBottom动画<Animated.View>和视图可以用<KeyboardAvoidingView behavior="padding">替换实现;
4.QQ聊天示例
视图大概结构
<View style={styles.container}>
<Text style={styles.nameStyle}>标题(QQ用户名)</Text>标题
<KeyboardAwareScrollView> 滚动视图,根据键盘显示隐藏高度会动态调整
<View></View>
<View onLayout={e => this.setState({scrollViewHeight: e.nativeEvent.layout.y})}/> //ScrollView最下面下面视图,获取ScrollView实际高度
</KeyboardAwareScrollView>
<View style={styles.senditemStyle}> 输入和发送视图
</View>
</View>
问题说明:KeyboardAwareScrollView长度变短之后,里面的内容并没有发生滚动。产生键盘覆盖 KeyboardAwareScrollView 内容的效果;
4.1实现类似QQ聊天效果,点击输入框以后可以继续停留在未弹出键盘的位置;
完整示例代码
import React, {Component} from "react";
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'
import {
Keyboard, Text, TextInput, TouchableOpacity, StyleSheet, View
} from "react-native";
export default class QQChatShowScene extends Component{
constructor(props){
super(props);
this.state = {
keyboardHeight:0, //键盘高度
lastOffset:0, //最后偏移位置
scrollViewHeight:0 //滚动视图的实际高度
};
}
componentDidMount() {
//监听键盘显示和隐藏
this.keyboardDidShowSub = Keyboard.addListener('keyboardDidShow', this.keyboardDidShow);
this.keyboardDidHideSub = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide);
}
//键盘显示
keyboardDidShow = (event) => {
//记录键盘的高度
this.setState({
keyboardHeight:event.endCoordinates.height
});
//滚动到未显示键盘之前y轴偏移的位置,KeyboardAwareScrollView视图变小,偏移位置上移键盘高度
this.scrollview.props.scrollToPosition(0, this.state.lastOffset+event.endCoordinates.height);
}
//键盘隐藏
keyboardDidHide = (event) => {
//滚动到显示键盘之前y轴偏移的位置,KeyboardAwareScrollView视图变大,偏移位置下移键盘高度
this.scrollview.props.scrollToPosition(0, this.state.lastOffset-this.state.keyboardHeight);
}
componentWillUnmount() {
//移除键盘监听
this.keyboardDidShowSub.remove();
this.keyboardDidHideSub.remove();
}
render(){
return (<View style={styles.container}>
<Text style={styles.nameStyle}>标题(QQ用户名)</Text>
<KeyboardAwareScrollView
innerRef={ref => {
this.scrollview = ref
}}
onScroll = {(event)=>{{
console.log(event.nativeEvent.contentOffset.x);//水平滚动距离
console.log(event.nativeEvent.contentOffset.y);//垂直滚动距离
this.setState({lastOffset:event.nativeEvent.contentOffset.y});//记录y轴滚动位置
}}}>
<Text>TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
ccccccccccccccccccccccccccccccccccccTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccccccccc</Text>
<View onLayout={e => this.setState({scrollViewHeight: e.nativeEvent.layout.y})}/>
</KeyboardAwareScrollView>
<View style={styles.senditemStyle}>
<TextInput placeholder='请输入' style={styles.textInputStyle}/><TouchableOpacity style={styles.sendBtnStyle}><Text>发送</Text></TouchableOpacity>
</View>
</View>);
}
}
let styles = StyleSheet.create({
container:{
flex:1
},
nameStyle:{
height:45,
width:'100%',
textAlign:'center',
textAlignVertical:'center'
},
senditemStyle:{
height:55,
width:'100%',
flexDirection:'row',
backgroundColor:'#0f0',
alignItems:'center'
},
textInputStyle:{
flex:4
},
sendBtnStyle:{
flex:1
}
});
4.2键盘显示或隐藏总是滚到底部
//键盘显示
keyboardDidShow = (event) => {
//记录键盘的高度
this.setState({
keyboardHeight:event.endCoordinates.height
});
//滚动到未显示键盘之前y轴偏移的位置,KeyboardAwareScrollView视图变小,偏移位置上移键盘高度
// this.scrollview.props.scrollToPosition(0, this.state.lastOffset+event.endCoordinates.height);
// 键盘展开
// 键盘展开时 scrollview 变小,内容位置不会发生变化,所以减去键盘高度滑动到最底
this.scrollview.props.scrollToPosition(0, this.state.scrollViewHeight-event.endCoordinates.height);
}
//键盘隐藏
keyboardDidHide = (event) => {
//滚动到显示键盘之前y轴偏移的位置,KeyboardAwareScrollView视图变大,偏移位置下移键盘高度
//this.scrollview.props.scrollToPosition(0, this.state.lastOffset-this.state.keyboardHeight);
// 键盘关闭时 scrollView 变大,所以再减一个键盘高度
this.scrollview.props.scrollToPosition(0, this.state.scrollViewHeight-2*this.state.keyboardHeight);
}
参考:
https://blog.csdn.net/sinat_17775997/article/details/72953940
https://blog.csdn.net/weixin_39330484/article/details/86687951