详解React-Native解决键盘遮挡问题(Keyboard遮挡问题)


Posted in Javascript onJuly 13, 2017

本文介绍了React-Native键盘遮挡问题,分享给大家

在开发中经常遇到需要输入的地方,RN给我们提过的TextInput虽然好用,可惜并没有处理遮挡问题。

很多时候键盘弹出来都会遮挡住编辑框,让人很头疼。

本来想在js.coach 库里面找一找第三方的插件,看到最好的一个就是React-native-keyboard-spacer了,然而我们还差一个东西,那就是获取键盘的高度。

这个我也查了半天并没有提供,获取没找到吧。于是只好自己写原生模块去获取键盘的高度了。

关于原生iOS获取键盘高度我就不多说了,网上一大堆,我直接贴上我的代码,自己根据RN写的原生模块:

// 
// KeyboardHeight.h 
// Jicheng6 
// 
// Created by guojicheng on 16/11/7. 
// Copyright © 2016年 Facebook. All rights reserved. 
// 
 
#import <UIKit/UIKit.h> 
#import "RCTEventEmitter.h" 
#import "RCTBridgeModule.h" 
 
@interface KeyboardHeight : RCTEventEmitter<RCTBridgeModule> 
 
-(void)heightChanged:(int)height; 
 
@property (nonatomic, assign)int kbHeight; 
 
@end
// 
// KeyboardHeight.m 
// Jicheng6 
// 
// Created by guojicheng on 16/11/7. 
// Copyright © 2016年 Facebook. All rights reserved. 
// 
 
#import "KeyboardHeight.h" 
 
@implementation KeyboardHeight 
 
RCT_EXPORT_MODULE(); 
 
- (instancetype)init 
{ 
 self = [super init]; 
 if (self) { 
  self.kbHeight = 0; 
  [[NSNotificationCenter defaultCenter] addObserver:self 
                       selector:@selector(keyboardDidShow:) 
                         name:UIKeyboardDidShowNotification 
                        object:nil]; 
 } 
 return self; 
} 
 
-(void)keyboardDidShow:(NSNotification*) aNotification 
{ 
 //获取键盘的高度 
 NSDictionary *userInfo = [aNotification userInfo]; 
 NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]; 
 CGRect keyboardRect = [aValue CGRectValue]; 
 if (_kbHeight != keyboardRect.size.height){ 
  _kbHeight = keyboardRect.size.height; 
  [self heightChanged:_kbHeight]; 
 } 
} 
 
RCT_REMAP_METHOD(getKBHeight, 
         resolver:(RCTPromiseResolveBlock)resolve 
         rejecter:(RCTPromiseRejectBlock)reject) 
{ 
 resolve([[NSNumber alloc]initWithInt:_kbHeight]); 
} 
 
- (NSArray<NSString *> *)supportedEvents 
{ 
 return @[@"heightChanged"]; 
} 
 
-(void)heightChanged:(int)height 
{ 
 [self sendEventWithName:@"heightChanged" body:[NSNumber numberWithUnsignedInt:height]]; 
} 
 
@end

这里其实我前面的博客也说过,一开始我想的是通过RCT_REMAP_METHOD去获得高度,可惜在键盘第一次弹出的时候,并不是弹出之后的高度,获取之后依然是0,所以添加了一个监听函数heightChanged,当记录的值和改变的值不一致时,调用监听函数,将值传给JS端。这样就可以在检测变化之后JS端做相应的变化。

好了,原生模块封装好了,接下来看js方面,这个也是老话题了,前面的博客都说了,直接贴代码:

import React, { Component } from 'react'; 
import { 
  AppRegistry, 
  StyleSheet, 
  Text, 
  View, 
  TouchableOpacity, 
  Alert, 
  TextInput, 
  PixelRatio, 
  Linking, 
  Keyboard, 
  NativeEventEmitter, 
} from 'react-native'; 
 
var Dimensions = require('Dimensions'); 
var ScreenWidth = Dimensions.get('window').width; 
var ScreenHeight = Dimensions.get('window').height; 
 
var kbHeight = require('NativeModules').KeyboardHeight; 
const kbHeightEvt = new NativeEventEmitter(kbHeight);
componentWillMount() { 
    this.heightChanged = kbHeightEvt.addListener('heightChanged', this._heightChanged.bind(this)); 
  } 
  componentDidMount() { 
 
  } 
  componentWillUnmount() { 
    this.heightChanged.remove(); 
  } 
  _heightChanged(data){ 
    // console.log(data); 
    this.keyboardHeight = data; 
    this.changeMarginTop();//这里我是处理高度的 
  }

这里已经拿到高度,接下来就好办了,就是加减问题。

我们需要拿到输入框在屏幕中的位置,然后和键盘的高度做比较,输入框的位置我们通过onLayout获取:

onLayoutParent(event){ 
    if (this.orgLayoutParent == null){//获取的父组件的位置,因为要用到计算 
      this.orgLayoutParent = event.nativeEvent.layout; 
    } 
    console.log('parent layout: ', event.nativeEvent.layout); 
  } 
  onLayoutMail(event){//获取输入框的位置,这个位置是相对父组件的位置,所以上面需要获得父组件的 
    this.layoutMail = event.nativeEvent.layout; 
  } 
  onFocusMail(event){ 
    this.focusName = 'mail';//定义一个标识,可以区分不同输入框 
    this.changeMarginTop();//统一处理高度的函数 
  } 
  onSubmitMail(){ 
    drawLayout.setKBMoveY(0);//当输入完毕时,重置回原来的状态 
  } 
  changeMarginTop(){//计算移动的距离 
    var layout = null; 
    if (this.focusName == 'mail'){ 
      layout = this.layoutMail; 
    } 
    if (layout && this.orgLayoutParent.y + layout.y + layout.height > ScreenHeight - this.keyboardHeight){ 
      drawLayout.setKBMoveY(-(this.orgLayoutParent.y + layout.y + layout.height - ScreenHeight + this.keyboardHeight)); 
    }else{//不对的置零处理 
      drawLayout.setKBMoveY(0); 
    } 
  } 
  render() { 
    return ( 
      <View style={[styles.container, this.props.style ? this.props.style : {}]} onLayout={this.onLayoutParent.bind(this)}> 
        <View style={[styles.viewStyle, {marginTop: 10}]} onLayout={this.onLayoutMail.bind(this)}>//这里获取的是相对位置哦 
          <TextInput style={styles.textInputStyle} 
            onChangeText={this.onTextChange.bind(this)} 
            value={this.state.emailPath} 
            placeholder={'请输入邮箱'} 
            onFocus={this.onFocusMail.bind(this)}//当获取到焦点时触发 
            onSubmitEditing={this.onSubmitMail.bind(this)}/>//点击回车时的调用,这里可以根据需求去做 
          <TouchableOpacity onPress={this.onSubmitSend.bind(this)}> 
            <View style={[styles.sendButtonView, {}]}> 
              <Text style={styles.sendButtonText}> 
                发送 
              </Text> 
            </View> 
          </TouchableOpacity> 
        </View> 
      </View> 
    ); 
  }

如果你是当前一个组件一个页面,就没必要像我这样做了,加了一个global,去记录它们的祖父组件(主要是整个页面向上移动)

距离我们也都算好了,接下来就是给drawLayout加一个动画,然后动起来不要那么突兀。

import React, { Component } from 'react'; 
import { 
 StyleSheet, 
 Text, 
 View, 
 TouchableOpacity, 
 Animated, 
} from 'react-native'; 
 
import SendEmail from './SendEmail'; 
 
export default class DrawLayout extends Component { 
 constructor(props){ 
  super(props); 
  this.state={ 
   kbShowY: new Animated.Value(0),//设置动画的初始值 
  }; 
  global.drawLayout = this;//这里将自己保存到global里面,方便它的子组件调用 
 } 
 setKBMoveY(y){ 
  Animated.timing(//这里用的是timing均匀变化,具体的参数,可以参考RN的文档,写的很详细了,这里就不??铝恕 
   this.state.kbShowY,{ 
    toValue: y,//变化到目的位置 
    delay: 250,//延时250毫秒 
   }, 
  ).start();//开始 
 } 
 componentWillUnmount() { 
  global.drawLayout = null;//降这个值赋值为空 
 } 
  
 render() { 
  return ( 
   <Animated.View style={[styles.container, {marginTop: this.state.kbShowY}]} >//使用Animated.View 
    <SendEmail style={{marginTop: 10}}/> 
   </Animated.View> 
  ); 
 } 
}

这就大功告成了。接着截图看看效果,虽然有动画,没法弄动态图

详解React-Native解决键盘遮挡问题(Keyboard遮挡问题)  

详解React-Native解决键盘遮挡问题(Keyboard遮挡问题)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Code:loadScript( )加载js的功能函数
Feb 02 Javascript
CSDN轮换广告图片轮换效果
Mar 27 Javascript
jQuery-Easyui 1.2 实现多层菜单效果的代码
Jan 13 Javascript
jQuery Validate 验证,校验规则写在控件中的具体实例
Feb 27 Javascript
Vuex之理解Getters的用法实例
Apr 19 Javascript
详解如何提高 webpack 构建 Vue 项目的速度
Jul 03 Javascript
js学习总结_基于数据类型检测的四种方式(必看)
Jul 04 Javascript
微信小程序使用request网络请求操作实例
Dec 15 Javascript
AngularJs点击状态值改变背景色的实例
Dec 18 Javascript
javascript匿名函数中的'return function()'作用
Oct 15 Javascript
element-ui 中使用upload多文件上传只请求一次接口
Jul 19 Javascript
如何实现iframe父子传参通信
Feb 05 Javascript
详解vue-cli + webpack 多页面实例配置优化方法
Jul 13 #Javascript
Angular限制input框输入金额(是小数的话只保留两位小数点)
Jul 13 #Javascript
js实现图片上传预览原理分析
Jul 13 #Javascript
vue.js数据绑定的方法(单向、双向和一次性绑定)
Jul 13 #Javascript
Easyui Datagrid自定义按钮列(最后面的操作列)
Jul 13 #Javascript
AngularJS 实现点击按钮获取验证码功能实例代码
Jul 13 #Javascript
解决Vue页面固定滚动位置的处理办法
Jul 13 #Javascript
You might like
vBulletin HACK----显示话题大小和打开新窗口于论坛索引页
2006/10/09 PHP
解析:通过php socket并借助telnet实现简单的聊天程序
2013/06/18 PHP
ECMall支持SSL连接邮件服务器的配置方法详解
2014/05/19 PHP
PHP下使用mysqli的函数连接mysql出现warning: mysqli::real_connect(): (hy000/1040): ...
2016/02/14 PHP
PHP实现的多进程控制demo示例
2019/07/22 PHP
php进行md5加密简单实例方法
2019/09/19 PHP
纯js实现的论坛常用的运行代码的效果
2008/07/15 Javascript
JQuery 学习笔记 选择器之三
2009/07/23 Javascript
javascript 必知必会之closure
2009/09/21 Javascript
jQuery实现tag便签去重效果的方法
2015/01/20 Javascript
JavaScript代码性能优化总结篇
2016/05/15 Javascript
浅谈JavaScript中promise的使用
2017/01/11 Javascript
JavaScript正则表达式的贪婪匹配和非贪婪匹配
2017/09/05 Javascript
详解Angular5 服务端渲染实战
2018/01/04 Javascript
ES6基础之解构赋值(destructuring assignment)
2019/02/21 Javascript
小程序中this.setData的使用和注意事项
2019/08/28 Javascript
javascript设计模式 ? 命令模式原理与用法实例分析
2020/04/20 Javascript
详解JavaScript类型判断的四种方法
2020/10/21 Javascript
Vue中nprogress页面加载进度条的方法实现
2020/11/13 Javascript
[01:56]生活中的妖精之七夕特别档
2016/08/09 DOTA
python基础教程之lambda表达式使用方法
2014/02/12 Python
Python中在for循环中嵌套使用if和else语句的技巧
2016/06/20 Python
Python实现的朴素贝叶斯分类器示例
2018/01/06 Python
PyCharm导入python项目并配置虚拟环境的教程详解
2019/10/13 Python
Python如何截图保存的三种方法(小结)
2020/09/01 Python
几款好用的python工具库(小结)
2020/10/20 Python
CSS3的 fit-content实现水平居中
2017/09/07 HTML / CSS
为什么Runtime.exec(“ls”)没有任何输出?
2014/10/03 面试题
会计专业推荐信
2013/10/29 职场文书
好的演讲稿开场白
2013/12/30 职场文书
环保倡议书格式范文
2014/05/14 职场文书
小学生放飞梦想演讲稿
2014/08/26 职场文书
纪念一二九运动演讲稿
2014/09/16 职场文书
2016年小学六一儿童节活动总结
2016/04/06 职场文书
python识别围棋定位棋盘位置
2021/07/26 Python
Django实现WebSocket在线聊天室功能(channels库)
2021/09/25 Python