首頁 >web前端 >js教程 >React-Native遇到Keyboard遮蔽問題該如何解決?

React-Native遇到Keyboard遮蔽問題該如何解決?

零下一度
零下一度原創
2017-07-16 15:26:301560瀏覽

    在開發中經常遇到需要輸入的地方,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 &#39;react&#39;; 
import { 
  AppRegistry, 
  StyleSheet, 
  Text, 
  View, 
  TouchableOpacity, 
  Alert, 
  TextInput, 
  PixelRatio, 
  Linking, 
  Keyboard, 
  NativeEventEmitter, 
} from &#39;react-native&#39;; 
 
var Dimensions = require(&#39;Dimensions&#39;); 
var ScreenWidth = Dimensions.get(&#39;window&#39;).width; 
var ScreenHeight = Dimensions.get(&#39;window&#39;).height; 
 
var kbHeight = require(&#39;NativeModules&#39;).KeyboardHeight; 
const kbHeightEvt = new NativeEventEmitter(kbHeight);


componentWillMount() { 
    this.heightChanged = kbHeightEvt.addListener(&#39;heightChanged&#39;, 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(&#39;parent layout: &#39;, event.nativeEvent.layout); 
  } 
  onLayoutMail(event){//获取输入框的位置,这个位置是相对父组件的位置,所以上面需要获得父组件的 
    this.layoutMail = event.nativeEvent.layout; 
  } 
  onFocusMail(event){ 
    this.focusName = &#39;mail&#39;;//定义一个标识,可以区分不同输入框 
    this.changeMarginTop();//统一处理高度的函数 
  } 
  onSubmitMail(){ 
    drawLayout.setKBMoveY(0);//当输入完毕时,重置回原来的状态 
  } 
  changeMarginTop(){//计算移动的距离 
    var layout = null; 
    if (this.focusName == &#39;mail&#39;){ 
      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={&#39;请输入邮箱&#39;} 
            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 &#39;react&#39;; 
import { 
 StyleSheet, 
 Text, 
 View, 
 TouchableOpacity, 
 Animated, 
} from &#39;react-native&#39;; 
 
import SendEmail from &#39;./SendEmail&#39;; 
 
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遮蔽問題該如何解決?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn