详解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 相关文章推荐
非常不错的功能强大代码简单的管理菜单美化版
Jul 09 Javascript
javascript 面向对象编程 聊聊对象的事
Sep 17 Javascript
数组方法解决JS字符串连接性能问题有争议
Jan 12 Javascript
基于jquery实现拆分姓名的方法(纯JS版)
May 08 Javascript
node.js不得不说的12点内容
Jul 14 Javascript
javaScript中push函数用法实例分析
Jun 08 Javascript
canvas时钟效果
Feb 16 Javascript
利用n工具轻松管理Node.js的版本
Apr 21 Javascript
Angular实现预加载延迟模块的示例
Oct 12 Javascript
vue.js数据绑定操作详解
Apr 23 Javascript
更改BootStrap popover的默认样式及popover简单用法
Sep 13 Javascript
使用JavaScript破解web
Sep 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开发文件系统实例讲解
2006/10/09 PHP
用PHP查询域名状态whois的类
2006/11/25 PHP
MySql 按时间段查询数据方法(实例说明)
2008/11/02 PHP
php 文件上传实例代码
2012/04/19 PHP
PHP操作Memcache实例介绍
2013/06/14 PHP
PHP脚本监控Nginx 502错误并自动重启php-fpm
2015/05/13 PHP
phalcon框架使用指南
2016/02/23 PHP
Yii2分页的使用及其扩展方法详解
2016/05/23 PHP
浅谈Sizzle的“编译原理”
2015/04/14 Javascript
jquery判断对象是否为空并遍历对象的简单实例
2016/07/26 Javascript
jQuery插件FusionCharts实现的2D饼状图效果【附demo源码下载】
2017/03/03 Javascript
JS实现简单抖动效果
2017/06/01 Javascript
解析Vue 2.5的Diff算法
2017/11/28 Javascript
vue-cli 使用vue-bus来全局控制的实例讲解
2018/09/15 Javascript
vue+webpack中配置ESLint
2018/11/07 Javascript
简单了解小程序+node梳理登陆流程
2019/06/24 Javascript
vue-week-picker实现支持按周切换的日历
2019/06/26 Javascript
[40:19]2018完美盛典CS.GO表演赛
2018/12/17 DOTA
Python实现将绝对URL替换成相对URL的方法
2015/06/28 Python
Python获取邮件地址的方法
2015/07/10 Python
Python实现基于C/S架构的聊天室功能详解
2018/07/07 Python
Python如何获得百度统计API的数据并发送邮件示例代码
2019/01/27 Python
Python实现Selenium自动化Page模式
2019/07/14 Python
django用户登录验证的完整示例代码
2019/07/21 Python
Django框架表单操作实例分析
2019/11/04 Python
五种Python转义表示法
2020/11/27 Python
戴尔新西兰官网:Dell New Zealand
2020/01/07 全球购物
世界上最好的野生海鲜和有机食品:Vital Choice
2020/01/16 全球购物
国窖1573广告词
2014/03/21 职场文书
希特勒经典演讲稿
2014/05/19 职场文书
大学文艺委员竞选稿
2015/11/19 职场文书
幼儿园小班开学寄语(2016秋季)
2015/12/03 职场文书
MySQL8.0.18配置多主一从
2021/06/21 MySQL
攻略丨滑雪究竟该选哪款对讲机?
2022/02/18 无线电
Android 中的类文件和类加载器详情
2022/06/05 Java/Android
Python 操作pdf pdfplumber读取PDF写入Exce
2022/08/14 Python