《React-Native系列》44、基于多个TextInput的键盘遮挡处理方案优化

react

曾经写过两篇关于在ReactNative上处理键盘遮挡输入表单TextInput的情况。建议读者能够先看看

1、《React-Native系列》33、 键盘遮挡问题处理

2、《React-Native系列》42、键盘遮挡问题官方处理方法KeyboardAvoidingView

曾经给出的解决方式,是使用ScrollView的scrollTo方法,将表单的输入域移动到可见区域(从键盘遮挡处移到键盘上方)。

这个方法存在下面问题:

1、移动距离的计算不精确

2、假设表单中有多个TextInput,怎么处理? 

今天,我们来给出个比較好的方案。

'use strict';

import React, { Component } from 'react';

import {

View,

Text,

ScrollView,

NativeModules,

TouchableOpacity,

TouchableHighlight,

AppRegistry,

Image,

Platform,

TextInput,

Dimensions,

Keyboard,

}from 'react-native';

var dismissKeyboard = require('dismissKeyboard');

const {width, height} = Dimensions.get('window');

import styles from '../styles/goods/Spec.css';

export default class Spec extends Component {

constructor(props) {

super(props);

this.state = {

groupValueList:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],

};

this.contentHeight = 0;

this.textInputView = null;//当前编辑的textInput

this.moveH = 0;//ScrollView滑动的距离

this.lastMoveH = 0;//保留上次滑动的距离

this.needMove = false;//弹出键盘时。textInputView是否须要滑动

}

componentWillMount(){

if (Platform.OS === 'ios') {

this.subscriptions = [

Keyboard.addListener('keyboardDidShow', this._keyboardDidShow),

Keyboard.addListener('keyboardDidHide', this._keyboardDidHide)

];

}

}

componentWillUnmount(){

if (Platform.OS === 'ios') {

this.subscriptions.forEach((sub) => sub.remove());

}

}

_keyboardDidShow = (e) => {

if(! this.textInputView) return ;

this.needMove = false;

this.refs[this.textInputView].measure((ox, oy, w, h, px, py)=>{

let leftHeight = height - py;//输入框距离底部的距离 = (屏幕的高度 - 当前TextInput的高度)

//输入框距离底部的距离小于键盘的高度,须要滑动

if( leftHeight < e.startCoordinates.height + 25 ){

this.needMove = true;

// 须要移动的距离

let moveHeight = 30 + (e.startCoordinates.height - leftHeight);

console.log("this.moveH=" + this.moveH,"this.contentHeight=" + this.contentHeight,"height=" + height);

//moveH 异常数据处理

if(this.moveH + height > this.contentHeight) {

this.moveH = this.contentHeight - height;

console.log("===error===");

}

this.lastMoveH = this.moveH;

this.refs.scroll.scrollTo({y:this.moveH + moveHeight ,x:0});

}

});

}

_keyboardDidHide = () => {

if(this.needMove){

this.refs.scroll.scrollTo({y:this.lastMoveH ,x:0});

}

this.textInputView = null;

}

/**

* 展示规格项组合项

*/

_renderGroupItem(item , i) {

let refId = i;

return (

<View key={i} style={{ marginLeft:15,borderTopWidth:1,

borderTopColor:'#DBDBDB',justifyContent:'center',height:70}}>

<TextInput

ref={ refId }

style={{

width:110,

alignSelf:'center',

borderWidth: 1,

borderColor:'#BDBDBD',

textAlign:'center',

fontSize:13,

color:'#333333',

height:25,

}}

maxLength={5}

placeholderTextColor="#b2b2b2"

placeholder="请输入价格"

multiline={false}

keyboardType="numeric"

returnKeyType={'done'}

value={"" }

onFocus={()=>{this.textInputView = refId}}

/>

</View>

);

}

render(){

return (

<View style={{flex: 1,backgroundColor: '#ffffff'}}>

<View/>

<ScrollView ref='scroll' onContentSizeChange ={(contentWidth, contentHeight)=>{

this.contentHeight = parseInt(contentHeight);

}}

onScrollEndDrag={(e)=>{

this.moveH = e.nativeEvent.contentOffset.y;

// console.log("this.moveH",this.moveH);

}}>

<View onStartShouldSetResponderCapture={(e)=>{dismissKeyboard();}}>

{ this.state.groupValueList.map((item,i)=>this._renderGroupItem(item,i)) }

</View>

</ScrollView>

</View>

);

}

}

AppRegistry.registerComponent('你的模块',() => Spec);



代码凝视比較具体了,可是这里还是简单说明下下面几个点:

1、仅仅对iOS平台进行处理。RN已经对Android做了键盘的处理

2、当前TextInput的高度

获取到当前正在被编辑的textInput ,this.textInputView 

在键盘弹出监听_keyboardDidShow 中,调用 this.refs[this.textInputView].measure((ox, oy, w, h, px, py)=>{});

此时的py就是当前TextInput在屏幕上的高度
       

3、 输入框距离底部的距离  (leftHeight)

       输入框距离底部的距离 = (屏幕的高度 - 当前TextInput在屏幕上的高度)

      推断leftHeight 是否大于键盘高度,假设大于键盘的高度,默认不处理。假设小于键盘的高度,那么说明TextInput被键盘覆盖

4、移动距离的计算

通过ScrollView的onScrollEndDrag方法,计算ScrollView滑动的距离。

  this.moveH = e.nativeEvent.contentOffset.y;

通过键盘的高度和leftHeight ,计算出须要移动的距离

5、moveH异常数据的处理

当高速滑动的时候,点击TextInput还是会出现移动距离错误的情况,由于ScrollView滑动的距离计算有误

譬如向下滑动到顶部后,继续滑动。this.moveH 会出现负数   。此情况不须要处理,由于TextInput在键盘上方

向上滑动究竟部后,继续滑动,this.moveH会有问题 ,此情况须要处理


解决方式:我们将moveH的数据纠正

假设 moveH + 屏幕的高度 大于 ScrollView内容的高度,说明moveH数值偏高,此时须要将moveH的值纠正为this.contentHeight - height,即:滑动到页面底部的状态。


          if(this.moveH + height > this.contentHeight) {

this.moveH = this.contentHeight - height;

console.log("===error===");

}


下图可见:moveH数据异常


界面展演示样例如以下:


以上都是基于 RN 0.29.2版本号。假设使用其它版本号。可能API会有不一致的情况。

假设您有更好的方案。希望能够交流,联系我见:与我联系

參考:

http://blog.csdn.net/lxq0426/article/details/51838653

http://blog.csdn.net/pz789as/article/details/53404352


以上是 《React-Native系列》44、基于多个TextInput的键盘遮挡处理方案优化 的全部内容, 来源链接: utcz.com/z/384246.html

回到顶部