详解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 相关文章推荐
js中的string.format函数代码
Aug 11 Javascript
jquery.qrcode在线生成二维码使用示例
Aug 21 Javascript
Jquery 的outerHeight方法使用介绍
Sep 11 Javascript
JavaScript通过元素的ID和name设置样式
Jul 08 Javascript
javascript通过元素id和name直接取得元素的方法
Apr 28 Javascript
JavaScript对Cookie进行读写操作实例
Jul 25 Javascript
js下拉选择框与输入框联动实现添加选中值到输入框的方法
Aug 17 Javascript
AngularJS基础 ng-href 指令用法
Aug 01 Javascript
Bootstrap轮播插件使用代码
Oct 11 Javascript
Angularjs中的$apply及优化使用详解
Jul 02 Javascript
Node.js系列之连接DB的方法(3)
Aug 30 Javascript
原生JS生成指定位数的验证码
Oct 28 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
php中$this-&amp;gt;含义分析
2009/11/29 PHP
PHP管理依赖(dependency)关系工具 Composer 安装与使用
2014/08/18 PHP
CI操作cookie的方法分析(基于helper类库)
2016/03/28 PHP
php魔法函数与魔法常量使用介绍
2017/07/23 PHP
详解PHP版本兼容之openssl调用参数
2018/07/25 PHP
慎用 somefunction.prototype 分析
2009/06/02 Javascript
jQuery使用after()方法在元素后面添加多项内容的方法
2015/03/26 Javascript
js比较日期大小的方法
2015/05/12 Javascript
js确认框confirm()用法实例详解
2016/01/07 Javascript
关于获取DIV内部内容报错的原因分析及解决办法
2016/01/29 Javascript
再谈javascript常见错误及解决方法
2016/09/16 Javascript
详解微信小程序开发—你期待的分享功能来了,微信小程序序新增5大功能
2016/12/23 Javascript
详解vue2.0脚手架的webpack 配置文件分析
2017/05/27 Javascript
原生JS实现瀑布流插件
2018/02/06 Javascript
详解iview的checkbox多选框全选时校验问题
2019/06/10 Javascript
[10:18]2018DOTA2国际邀请赛寻真——Fnatic能否笑到最后?
2018/08/14 DOTA
Python创建xml的方法
2015/03/10 Python
分享一个常用的Python模拟登陆类
2015/03/29 Python
python爬虫实现教程转换成 PDF 电子书
2017/02/19 Python
Python 实现异步调用函数的示例讲解
2018/10/14 Python
python 和c++实现旋转矩阵到欧拉角的变换方式
2019/12/04 Python
基于python及pytorch中乘法的使用详解
2019/12/27 Python
Python程序慢的重要原因
2020/09/04 Python
python re.match()用法相关示例
2021/01/27 Python
详解Html5页面实现下载文件(apk、txt等)的三种方式
2018/10/22 HTML / CSS
html5简介及新增功能介绍
2020/05/18 HTML / CSS
介绍一些UNIX常用简单命令
2014/11/11 面试题
暑期实习鉴定
2013/12/16 职场文书
《藤野先生》教学反思
2014/02/19 职场文书
计算机专业应届生求职信
2014/04/06 职场文书
群众路线教育实践活动民主生活会个人检查对照思想汇报
2014/10/04 职场文书
社区母亲节活动总结
2015/02/10 职场文书
资料员岗位职责范本
2015/04/13 职场文书
教学质量月活动总结
2015/05/11 职场文书
解决Jenkins集成SonarQube遇到的报错问题
2021/07/15 Java/Android
Python读取和写入Excel数据
2022/04/20 Python