詳解React-Native解決鍵盤遮擋問(wèn)題(Keyboard遮擋問(wèn)題)
本文介紹了React-Native鍵盤遮擋問(wèn)題,分享給大家
在開發(fā)中經(jīng)常遇到需要輸入的地方,RN給我們提過(guò)的TextInput雖然好用,可惜并沒有處理遮擋問(wèn)題。
很多時(shí)候鍵盤彈出來(lái)都會(huì)遮擋住編輯框,讓人很頭疼。
本來(lái)想在js.coach 庫(kù)里面找一找第三方的插件,看到最好的一個(gè)就是React-native-keyboard-spacer了,然而我們還差一個(gè)東西,那就是獲取鍵盤的高度。
這個(gè)我也查了半天并沒有提供,獲取沒找到吧。于是只好自己寫原生模塊去獲取鍵盤的高度了。
關(guān)于原生iOS獲取鍵盤高度我就不多說(shuō)了,網(wǎng)上一大堆,我直接貼上我的代碼,自己根據(jù)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
這里其實(shí)我前面的博客也說(shuō)過(guò),一開始我想的是通過(guò)RCT_REMAP_METHOD去獲得高度,可惜在鍵盤第一次彈出的時(shí)候,并不是彈出之后的高度,獲取之后依然是0,所以添加了一個(gè)監(jiān)聽函數(shù)heightChanged,當(dāng)記錄的值和改變的值不一致時(shí),調(diào)用監(jiān)聽函數(shù),將值傳給JS端。這樣就可以在檢測(cè)變化之后JS端做相應(yīng)的變化。
好了,原生模塊封裝好了,接下來(lái)看js方面,這個(gè)也是老話題了,前面的博客都說(shuō)了,直接貼代碼:
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();//這里我是處理高度的
}
這里已經(jīng)拿到高度,接下來(lái)就好辦了,就是加減問(wèn)題。
我們需要拿到輸入框在屏幕中的位置,然后和鍵盤的高度做比較,輸入框的位置我們通過(guò)onLayout獲取:
onLayoutParent(event){
if (this.orgLayoutParent == null){//獲取的父組件的位置,因?yàn)橐玫接?jì)算
this.orgLayoutParent = event.nativeEvent.layout;
}
console.log('parent layout: ', event.nativeEvent.layout);
}
onLayoutMail(event){//獲取輸入框的位置,這個(gè)位置是相對(duì)父組件的位置,所以上面需要獲得父組件的
this.layoutMail = event.nativeEvent.layout;
}
onFocusMail(event){
this.focusName = 'mail';//定義一個(gè)標(biāo)識(shí),可以區(qū)分不同輸入框
this.changeMarginTop();//統(tǒng)一處理高度的函數(shù)
}
onSubmitMail(){
drawLayout.setKBMoveY(0);//當(dāng)輸入完畢時(shí),重置回原來(lái)的狀態(tài)
}
changeMarginTop(){//計(jì)算移動(dòng)的距離
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{//不對(duì)的置零處理
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)}>//這里獲取的是相對(duì)位置哦
<TextInput style={styles.textInputStyle}
onChangeText={this.onTextChange.bind(this)}
value={this.state.emailPath}
placeholder={'請(qǐng)輸入郵箱'}
onFocus={this.onFocusMail.bind(this)}//當(dāng)獲取到焦點(diǎn)時(shí)觸發(fā)
onSubmitEditing={this.onSubmitMail.bind(this)}/>//點(diǎn)擊回車時(shí)的調(diào)用,這里可以根據(jù)需求去做
<TouchableOpacity onPress={this.onSubmitSend.bind(this)}>
<View style={[styles.sendButtonView, {}]}>
<Text style={styles.sendButtonText}>
發(fā)送
</Text>
</View>
</TouchableOpacity>
</View>
</View>
);
}
如果你是當(dāng)前一個(gè)組件一個(gè)頁(yè)面,就沒必要像我這樣做了,加了一個(gè)global,去記錄它們的祖父組件(主要是整個(gè)頁(yè)面向上移動(dòng))
距離我們也都算好了,接下來(lái)就是給drawLayout加一個(gè)動(dòng)畫,然后動(dòng)起來(lái)不要那么突兀。
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),//設(shè)置動(dòng)畫的初始值
};
global.drawLayout = this;//這里將自己保存到global里面,方便它的子組件調(diào)用
}
setKBMoveY(y){
Animated.timing(//這里用的是timing均勻變化,具體的參數(shù),可以參考RN的文檔,寫的很詳細(xì)了,這里就不啰嗦了。
this.state.kbShowY,{
toValue: y,//變化到目的位置
delay: 250,//延時(shí)250毫秒
},
).start();//開始
}
componentWillUnmount() {
global.drawLayout = null;//降這個(gè)值賦值為空
}
render() {
return (
<Animated.View style={[styles.container, {marginTop: this.state.kbShowY}]} >//使用Animated.View
<SendEmail style={{marginTop: 10}}/>
</Animated.View>
);
}
}
這就大功告成了。接著截圖看看效果,雖然有動(dòng)畫,沒法弄?jiǎng)討B(tài)圖

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
React使用setState更新數(shù)組的方法示例(追加新數(shù)據(jù))
在?React?中,setState?是管理組件狀態(tài)的核心方法之一,然而,當(dāng)我們需要更新狀態(tài)中的數(shù)組時(shí),如何高效且安全地操作變得尤為關(guān)鍵,本文將詳細(xì)解析以下代碼的實(shí)現(xiàn)邏輯,幫助你掌握在?React?中追加數(shù)組數(shù)據(jù)的最佳實(shí)踐,需要的朋友可以參考下2025-03-03
React實(shí)現(xiàn)控制減少useContext導(dǎo)致非必要的渲染詳解
這篇文章主要介紹了React如何有效減少使用useContext導(dǎo)致的不必要渲染,使用useContext在改變一個(gè)數(shù)據(jù)時(shí),是通過(guò)自己逐級(jí)查找對(duì)比改變的數(shù)據(jù)然后渲染,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11
React實(shí)現(xiàn)翻頁(yè)時(shí)鐘的代碼示例
本文給大家介紹了React實(shí)現(xiàn)翻頁(yè)時(shí)鐘的代碼示例,翻頁(yè)時(shí)鐘把數(shù)字分為上下兩部分,翻頁(yè)效果的實(shí)現(xiàn)需要通過(guò)設(shè)置 position 把所有的數(shù)組放在同一個(gè)位置疊加起來(lái),文中有詳細(xì)的代碼講解,需要的朋友可以參考下2023-08-08
React服務(wù)端渲染和同構(gòu)的實(shí)現(xiàn)
本文主要介紹了React服務(wù)端渲染和同構(gòu)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04

