ReactNative: 使用键盘避免视图KeyboardAvoidingView组件实现键盘自适应

一、简介

在前面使用了TextInput实现了文本输入和搜索功能,一般情况下,我们会通过样式设置把控键盘弹起后与视图的间距,以至于不会挡住某些视图。但是,如果视图上的组件比较多,键盘的弹起覆盖某些视图几乎是无法避免的。ReactNative中就提供了一个KeyboardAvoidingView组件来解决这个问题。使用了这个组件后,它会帮助自动完成键盘的自适应,通过偏移避免其他组件被键盘遮盖。

 

二、API

KeyboardAvoidingView组件提供了3个比较重要的属性,分别是behavior、contentContainerStyle、keyboardVerticalOffset。behavior译为行为,这里指键盘避免视图组件的位移焦点。contentContainerStyle是该组件内部视图的样式布局。keyboardVerticalOffset则是键盘的竖直偏移距离。如下:

//位移的参照焦点有三种:height:以高度为焦点  position:以位置为焦点  padding:以边距为焦点
behavior: PropTypes.oneOf(['height', 'position', 'padding']),

//组件内容视图样式布局,只有采用‘ position’为焦点时,才会创建出这个内容视图
contentContainerStyle: ViewPropTypes.style,

//这是用户屏幕顶部与应用视图的距离,可以利用这个属性来补偿修正这段距离
keyboardVerticalOffset: PropTypes.number.isRequired,

KeyboardAvoidingView组件也提供了几个常用的方法,可以使用这几个方法手动来调整键盘的偏移。如下:

//键盘的相对高度
relativeKeyboardHeight(keyboardFrame: ScreenRect): number

//键盘改变时的回调
onKeyboardChange(event: ?KeyboardChangeEvent)

//键盘布局时的回调
onLayout(event: LayoutEvent)

//这个几个方法用到的对象如下
type Rect = {
  x: number,
  y: number,
  width: number,
  height: number,
};

type ScreenRect = {
  screenX: number,
  screenY: number,
  width: number,
  height: number,
};

type KeyboardChangeEvent = {
  startCoordinates?: ScreenRect, //起始位置
  endCoordinates: ScreenRect,    //终止位置 
  duration?: number,             //动画时间 
  easing?: string,          
};

type LayoutEvent = {
  nativeEvent: {
    layout: Rect,
  }
};

 

三、拓展

使用KeyboardAvoidingView组件时,可以搭配键盘组件Keyboard组件一起完成开发。键盘弹起和隐藏的过程,都可以使用键盘组件Keyboard进行监听。它提供了常用的几个监听名称和键盘相关数据,如下所示:

//监听名称
type KeyboardEventName =
     | 'keyboardWillShow'
     | 'keyboardDidShow'
     | 'keyboardWillHide'
     | 'keyboardDidHide'
     | 'keyboardWillChangeFrame'
     | 'keyboardDidChangeFrame';

//键盘数据
type KeyboardEventData = {
     endCoordinates: { 
        width: number,
        height: number,
        screenX: number,
        screenY: number,},
    };    

提供的几个方法比较简单,如下所示:

//给键盘添加监听
addListener(eventName: KeyboardEventName, callback: KeyboardEventListener)

//给键盘移除监听
removeListener(eventName: KeyboardEventName, callback: Function)

//移除键盘所有监听
removeAllListeners(eventName: KeyboardEventName)

//关闭键盘
dismiss()

 

四、使用

现在使用KeyboardAvoidingView组件来调节输入框的位置,示例如下:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';

import {
    AppRegistry,
    StyleSheet,
    View,
    TextInput,
    Dimensions,
    Keyboard,
    KeyboardAvoidingView
} from 'react-native';

let {height} = Dimensions.get('window');

export default class ReactNativeDemo extends Component {

    componentWillMount() {
        this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow',(KeyboardEventData)=>{

            console.log('Keyboard Shown');
            console.log(KeyboardEventData.endCoordinates.screenY);

            // KeyboardAvoidingView实例的方法,可以在监听事件中调用
            // const avoidingView = this.refs.KeyboardAvoidingView;
            // avoidingView.onKeyboardChange(KeyboardChangeEvent);
            // avoidingView.onLayout(LayoutEvent);
            // avoidingView.relativeKeyboardHeight(keyboardFrame);
        });

        this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', (KeyboardEventData)=>{

            console.log('Keyboard Hidden');
            console.log(KeyboardEventData.endCoordinates.screenY);

            // KeyboardAvoidingView实例的方法,可以在监听事件中调用
            // const avoidingView = this.refs.KeyboardAvoidingView;
            // avoidingView.onKeyboardChange(KeyboardChangeEvent);
            // avoidingView.onLayout(LayoutEvent);
            // avoidingView.relativeKeyboardHeight(keyboardFrame);
        });
    }

    componentWillUnmount() {
        this.keyboardDidShowListener.remove();
        this.keyboardDidHideListener.remove();
    }

    render() {
        return (
            <View style={[styles.flex,styles.bgColor]}>
                <KeyboardAvoidingView ref={'KeyboardAvoidingView'}
                                      behavior={'position'}
                                      keyboardVerticalOffset={10}
                                      contentContainerStyle={styles.avoidingView}>
                    <TextInput
                        style={styles.inputView}
                        placeholder='请输入关键字'
                        placeholderTextColor="black"
                        returnKeyType='search'
                        clearButtonMode='while-editing'
                        enablesReturnKeyAutomatically={true}
                    />
                </KeyboardAvoidingView>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    flex: {
        flex: 1
    },
    bgColor: {
      backgroundColor: 'white'
    },
    center: {
        alignItems: 'center',
        justifyContent: 'center',
    },
    font: {
        fontSize: 30,
        color: 'purple',
        textAlign: 'center'
    },
    avoidingView: {
        backgroundColor:'#DDD'
    },
    inputView:{
        height:100,
        borderWidth: 1,
        marginTop: height-111,
        marginRight:5,
        marginLeft: 5,
        paddingLeft: 5,
        borderColor:'red',
        borderRadius: 4
    },
});

AppRegistry.registerComponent('ReactNativeDemo', () => ReactNativeDemo);

打印结果如下:

2020-01-02 17:22:55.793 [info][tid:com.facebook.react.JavaScript] Keyboard Shown
2020-01-02 17:22:55.794 [info][tid:com.facebook.react.JavaScript] 407
2020-01-02 17:23:05.852 [info][tid:com.facebook.react.JavaScript] Keyboard Shown
2020-01-02 17:23:05.853 [info][tid:com.facebook.react.JavaScript] 407
2020-01-02 17:23:08.470 [info][tid:com.facebook.react.JavaScript] Keyboard Hidden
2020-01-02 17:23:08.470 [info][tid:com.facebook.react.JavaScript] 667

截图结果如下:1图为初始状态、2图为不使用KeyboardAvoidingView组件时输入框被键盘遮盖、图3使用了KeyboardAvoidingView组件时不会遮盖正常使用。

  

 

posted @ 2020-01-02 17:26  XYQ全哥  阅读(5370)  评论(0编辑  收藏  举报