Skip to content

怎么解决RN TextInput 被键盘遮挡的问题 #39

@dwqs

Description

@dwqs

在0.28版rn中,如果textinput的位置在靠近底部的位置,在textinput获取焦点后,ios上弹出的键盘会遮住textinput,导致用户无法输入;android上弹出键盘时,整个界面会被网上顶,textinput不会被遮住。

在0.28中,解决ios上该问题的方式是利用 ScrollView contentInset 属性,监听键盘的弹出和隐藏事件(keyboardWillShow/keyboardWillHide),获取键盘的高度,动态设置成 contentInset 的值。

将rn升级成0.33后,android和ios上都会出现TextInput 被键盘遮挡的问题,ios上原来的方式也不能解决此问题了。

在 ios 上,textinput 未获取焦点前:

image

获取焦点后:

image

textinput被键盘挡住了。android上有同样的问题。

解决这种情况的一种方式,监听键盘的弹出和隐藏事件,在ScrollView底部设置一个占位符组件,将占位符的高度设置成键盘的高度。

监听键盘事件:

this.keyboardShow = Platform.OS === 'ios' ?
    Keyboard.addListener('keyboardWillShow',this.updateKeyboardSpace.bind(this)) : Keyboard.addListener('keyboardDidShow',this.updateKeyboardSpace.bind(this));
this.keyboardHide = Platform.OS === 'ios' ?
    Keyboard.addListener('keyboardWillHide',this.resetKeyboardSpace.bind(this)) : Keyboard.addListener('keyboardDidHide',this.resetKeyboardSpace.bind(this));

在事件处理程序中,获取键盘高度:

updateKeyboardSpace(frames){
    if(!frames.endCoordinates){
       return;
    }
    let keyboardSpace = frames.endCoordinates.height;//获取键盘高度

    this.setState({
        keyboardSpace: keyboardSpace
    })
}

最后将高度传递给占位符组件:

<ScrollView>
    //其他元素 
    <KeyboardSpacer keyboardSpace={this.state.keyboardSpace}/>
</ScrollView>

KeyboardSpacer组件实现如下:

const styles = StyleSheet.create({
    container: {
        left: 0,
        right: 0,
        bottom: 0
    }
});

export default class KeyboardSpacer extends Component {
    constructor(){
        super();
    }

    static propTypes = {
        keyboardSpace: PropTypes.number
    };

    static defaultProps = {
        keyboardSpace: 0
    };

    render() {

        let {keyboardSpace} = this.props;
        return (
            <View style={[styles.container, { height: ~~keyboardSpace }]} />
        );
    }
}

效果如下:

image

这样子能解决部分场景,例如textInput的位置是靠近底部的。如果textinput框的位置是靠近页面上部的,那么textinput框会被顶上去,就会因超出ScrollView的视口范围而被“遮住”。

这时,就不能单纯的将键盘的高度给 KeyboardSpacer 了,而应该根据textinput在ScrollView视口的位置进行 KeyboardSpacer 高度的计算了。

在页面加载之后,能获取到 ScrollView的视口高度ViewportHeight,这个值是保持不变的。此外,也能拿到textinput距离ScrollViewd顶边的垂直距离InputY,这个值是固定的,不会随着页面的滚动而变化页面示意如下:

1

在界面滚动一定距离之后,页面示意如下:

2

红边表示此时ScrollView的顶边位置,虚线框表示textInput框的原位置,实体框表示textInput在页面滚动之后的位置。

页面滚动时,能获取到ScrollView已经滚动的偏移量 scrollY,此时,就能计算出此时 textInput 距离ScrollView视口底部的距离 InputToBottom:

InputToBottom = ViewportHeight - (InputY - scrollY + textInput的高度)

此时,应该根据InputToBottom与键盘高度的大小比较来设置 keyboardSpace:

keyboardHeight = frames.endCoordinates.height;  //键盘高度
keyboardSpace = InputToBottom >= keyboardHeight ? 0 : keyboardHeight - InputToBottom;

在图示页面的布局中,还有一个底部元素,因而在计算 keyboardHeight 时,因考虑下实际情况是否需要减去底部元素的高度或者ScrollView的marginBottom值。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions