React Native遮挡输入框问题

作者: c20cf494bb0f | 来源:发表于2016-12-22 11:23 被阅读0次

    最近在搞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]} />);
      }
    }
    

    相关文章

      网友评论

        本文标题:React Native遮挡输入框问题

        本文链接:https://www.haomeiwen.com/subject/cdvcvttx.html