欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-26 08:29:54
本文介绍了react-native键盘遮挡问题,分享给大家 在开发中经常遇到需要输入的地方,rn给我们提过的textinput虽然好用,可惜并没有处理遮挡问题。 很多时...

本文介绍了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遮挡问题)

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