详解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去除字符串的空格增强版(可以去除中间的空格)
Aug 26 Javascript
jquery下onpropertychange事件的绑定方法
Aug 01 Javascript
jquery1.83 之前所有与异步列队相关的模块详细介绍
Nov 13 Javascript
JavaScript编程中容易出BUG的几点小知识
Jan 31 Javascript
JavaScript对数字的判断与处理实例分析
Feb 02 Javascript
JQ技术实现注册页面带有校验密码强度
Jul 27 Javascript
JS上传图片预览插件制作(兼容到IE6)
Aug 07 Javascript
Angular4学习笔记router的简单使用
Mar 30 Javascript
jQuery实现模糊查询的方法分析
May 10 jQuery
页面内锚点定位及跳转方法总结(推荐)
Apr 24 Javascript
JS中的算法与数据结构之二叉查找树(Binary Sort Tree)实例详解
Aug 16 Javascript
Vue CLI3移动端适配(px2rem或postcss-plugin-px2rem)
Apr 27 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
Pain 全世界最小最简单的PHP模板引擎 (普通版)
2011/10/23 PHP
PHP设计模式之装饰者模式代码实例
2015/05/11 PHP
PHP弹出对话框技巧详细解读
2015/09/26 PHP
PHP简单实现上一页下一页功能示例
2016/09/14 PHP
thinkPHP+phpexcel实现excel报表输出功能示例
2017/06/06 PHP
Firefox 无法获取cssRules 的解决办法
2006/10/11 Javascript
js+jquery实现图片裁剪功能
2015/01/02 Javascript
Jquery使用css方法改变样式实例
2015/05/18 Javascript
javascript作用域链(Scope Chain)用法实例解析
2015/11/30 Javascript
Bootstrap每天必学之响应式导航、轮播图
2016/04/25 Javascript
jQuery实现的鼠标经过时变宽的效果(附demo源码)
2016/04/28 Javascript
详谈js中window.location.search的用法和作用
2017/02/13 Javascript
js实现登录与注册界面
2017/11/01 Javascript
Vue 2.5.2下axios + express 本地请求404的解决方法
2018/02/21 Javascript
Jquery的Ajax技术使用方法
2019/01/21 jQuery
解决Vue+Electron下Vuex的Dispatch没有效果问题
2019/05/20 Javascript
利用原生JS实现欢乐水果机小游戏
2020/04/23 Javascript
Node登录权限验证token验证实现的方法示例
2020/05/25 Javascript
微信小程序实现列表左右滑动
2020/11/19 Javascript
[01:57]2018DOTA2亚洲邀请赛赛前采访-iG
2018/04/03 DOTA
haskell实现多线程服务器实例代码
2013/11/26 Python
[原创]使用豆瓣提供的国内pypi源
2017/07/02 Python
使用Python实现从各个子文件夹中复制指定文件的方法
2018/10/25 Python
Python 通过requests实现腾讯新闻抓取爬虫的方法
2019/02/22 Python
基于django传递数据到后端的例子
2019/08/16 Python
菲律宾最大的网上花店和礼品店:PhilFlower.com
2018/02/09 全球购物
西班牙土拨鼠床垫公司,感觉在云端:Marmota
2019/03/18 全球购物
大学生找工作推荐信范文
2013/11/28 职场文书
自我评价正确写法范文
2013/12/10 职场文书
三方股份合作协议书
2014/10/13 职场文书
上课说话检讨书500字
2014/11/01 职场文书
合作与交流自我评价
2015/03/09 职场文书
2015年监理工作总结范文
2015/04/07 职场文书
《坐井观天》教学反思
2016/02/18 职场文书
浅谈JS的二进制家族
2021/05/09 Javascript
Python 详解通过Scrapy框架实现爬取百度新冠疫情数据流程
2021/11/11 Python