最近在搞React Native输入框,发现键盘弹起的时候输入框并未随着一起弹起,文档中也并没有明显的说明,作为一个iOS开发,当然是要试试用Native的方式来解决问题,React Native文档中原生模块中有介绍Native向JavaScript发送事件,所以,可以用Native来监听键盘弹出收起事件,然后发送给JavaScript。
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
@implementation CalendarManager
@synthesize bridge = _bridge;
- (void)calendarEventReminderReceived:(NSNotification *)notification
{
NSString *eventName = notification.userInfo[@"name"];
[self.bridge.eventDispatcher sendAppEventWithName:@"EventReminder"
body:@{@"name": eventName}];
}
@end
按照文档的说明,敲出代码之后发现sendAppEventWithName这个方法已经废弃了:
RCTEventDispatcher源码
根据提示信息使用RCTEventEmitter代替,官网并未更新这个类的使用,但是根据头文件提示:"RCTEventEmitter is an abstract base class to be used for modules that emit events to be observed by JS.",应该使用RCTEventEmitter子类来实现消息传递:
#import "CLRNEventEmitter.h"
#define CL_KEYBOARD_SHOW_EVENT @"keyboardWillShow"
#define CL_KEYBOARD_HIDE_EVENT @"keyboardWillHide"
@implementation CLRNEventEmitter
RCT_EXPORT_MODULE();
- (NSArray<NSString *> *)supportedEvents
{
return @[
CL_KEYBOARD_SHOW_EVENT,
CL_KEYBOARD_HIDE_EVENT
];
}
- (instancetype)init
{
if (self = [super init]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Keyboard Event
- (void)keyboardWillShow:(NSNotification *)notification
{
[self sendEvent:CL_KEYBOARD_SHOW_EVENT object:notification.userInfo];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
[self sendEvent:CL_KEYBOARD_HIDE_EVENT object:notification.userInfo];
}
#pragma mark -
#pragma mark - Base Function
- (void)sendEvent:(NSString *)eventName object:(id)object
{
[self sendEventWithName:eventName body:object];
}
@end
对应的js文件里面添加监听:
var keyboardEvent = new NativeEventEmitter(NativeModules.CLRNEventEmitter);
componentDidMount() {
this.keyboardWillShow = keyboardEvent.addListener('keyboardWillShow', this._keyboardWillShow.bind(this));
this.keyboardWillHide = keyboardEvent.addListener('keyboardWillHide', this._keyboardWillHide.bind(this));
}
componentWillUnmount() {
this.keyboardWillShow.remove();
this.keyboardWillHide.remove();
dismissKeyboard();
}
_keyboardWillShow(infoData) {
if (!infoData || !infoData.endCoordinates || !infoData.duration) return;
Animated.timing(this.state.loacationOffInputView, {
toValue: infoData.endCoordinates.height, // 目标值
duration: infoData.duration, // 动画时间
easing: Easing.keyboard // 缓动函数
}).start();
}
_keyboardWillHide(infoData) {
if (!infoData || !infoData.endCoordinates || !infoData.duration) return;
Animated.timing(this.state.loacationOffInputView, {
toValue: 0, // 目标值
duration: infoData.duration, // 动画时间
easing: Easing.keyboard, // 缓动函数
}).start();
}
以上是通过Native注册通知监听键盘弹出及消失,然后发送消息给JavaScript,JavaScript通过监听做对应的处理。后来咨询了一下js开发的同事,他给我提供了另一个使用js插件的方式解决:react-native-keyboard-spacer,安装只需一行命令,然后在对应的控件里面添加一行代码搞定:
npm install --save react-native-keyboard-spacer
//react-native-keyboard-spacer
import KeyboardSpacer from 'react-native-keyboard-spacer';
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Image,
View,
TextInput
} from 'react-native';
class DemoApp extends Component {
render() {
return (
<View style={[{flex: 1}]}>
{/* Some random image to show scaling */}
<Image source={{uri: 'http://img11.deviantart.net/072b/i/2011/206/7/0/the_ocean_cherry_tree_by_tomcadogan-d41nzsz.png', static: true}}
style={{flex: 1}}/>
{/* The text input to put on top of the keyboard */}
<TextInput style={{left: 0, right: 0, height: 45}}
placeholder={'Enter your text!'}/>
{/* The view that will animate to match the keyboards height */}
<KeyboardSpacer/>
</View>
);
}
}
AppRegistry.registerComponent('DemoApp', () => DemoApp);
//react-native-keyboard-spacer源码:
/**
* Created by andrewhurst on 10/5/15.
*/
import React, { Component, PropTypes } from 'react';
import {
Keyboard,
LayoutAnimation,
View,
Dimensions,
Platform,
StyleSheet
} from 'react-native';
const styles = StyleSheet.create({
container: {
left: 0,
right: 0,
bottom: 0,
},
});
// From: https://medium.com/man-moon/writing-modern-react-native-ui-e317ff956f02
const defaultAnimation = {
duration: 500,
create: {
duration: 300,
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity
},
update: {
type: LayoutAnimation.Types.spring,
springDamping: 200
}
};
export default class KeyboardSpacer extends Component {
static propTypes = {
topSpacing: PropTypes.number,
onToggle: PropTypes.func,
style: View.propTypes.style,
};
static defaultProps = {
topSpacing: 0,
onToggle: () => null,
};
constructor(props, context) {
super(props, context);
this.state = {
keyboardSpace: 0,
isKeyboardOpened: false
};
this._listeners = null;
this.updateKeyboardSpace = this.updateKeyboardSpace.bind(this);
this.resetKeyboardSpace = this.resetKeyboardSpace.bind(this);
}
componentDidMount() {
const updateListener = Platform.OS === 'android' ? 'keyboardDidShow' : 'keyboardWillShow';
const resetListener = Platform.OS === 'android' ? 'keyboardDidHide' : 'keyboardWillHide';
this._listeners = [
Keyboard.addListener(updateListener, this.updateKeyboardSpace),
Keyboard.addListener(resetListener, this.resetKeyboardSpace)
];
}
componentWillUnmount() {
this._listeners.forEach(listener => listener.remove());
}
updateKeyboardSpace(event) {
if (!event.endCoordinates) {
return;
}
let animationConfig = defaultAnimation;
if (Platform.OS === 'ios') {
animationConfig = LayoutAnimation.create(
event.duration,
LayoutAnimation.Types[event.easing],
LayoutAnimation.Properties.opacity,
);
}
LayoutAnimation.configureNext(animationConfig);
// get updated on rotation
const screenHeight = Dimensions.get('window').height;
// when external physical keyboard is connected
// event.endCoordinates.height still equals virtual keyboard height
// however only the keyboard toolbar is showing if there should be one
const keyboardSpace = (screenHeight - event.endCoordinates.screenY) + this.props.topSpacing;
this.setState({
keyboardSpace,
isKeyboardOpened: true
}, this.props.onToggle(true, keyboardSpace));
}
resetKeyboardSpace(event) {
let animationConfig = defaultAnimation;
if (Platform.OS === 'ios') {
animationConfig = LayoutAnimation.create(
event.duration,
LayoutAnimation.Types[event.easing],
LayoutAnimation.Properties.opacity,
);
}
LayoutAnimation.configureNext(animationConfig);
this.setState({
keyboardSpace: 0,
isKeyboardOpened: false
}, this.props.onToggle(false, 0));
}
render() {
return (
<View style={[styles.container, { height: this.state.keyboardSpace }, this.props.style]} />);
}
}
网友评论