KeyboardAvoidingView - 当键盘隐藏时重置高度

21

我正在使用React Native的KeyboardAvoidingView来设置我的View高度,当键盘显示时。但是当我关闭应用程序中的键盘时,View的高度没有改变回原始值。

<KeyboardAvoidingView behavior="height" style={styles.step}>
  <View style={styles.stepHeader}>
    // my content
  </View>
</KeyboardAvoidingView>

在我打开和关闭键盘之前,带有红色轮廓的视图占据了整个空间。

截图


我遇到了同样的问题。[iOS] 你找到解决方案了吗? - Edgar
1
@Edgar 对于一些情况,我转而使用以下这个包,它可以工作,但 RN 提供的组件仍然无法正常工作。https://github.com/APSL/react-native-keyboard-aware-scroll-view - mxmtsk
5个回答

26

关于Nisarg的答案,以下是更详细的解释。

在构造函数中为KeyboardAvoidingView创建一个键。

constructor(props) {
    this.state = {
      keyboardAvoidingViewKey: 'keyboardAvoidingViewKey',
    }
}

在键盘将要隐藏和已经隐藏时添加监听器(并在willUnmount中移除它)

import { KeyboardAvoidingView, Keyboard, Platform } from 'react-native'

componentDidMount() {
    // using keyboardWillHide is better but it does not work for android
    this.keyboardHideListener = Keyboard.addListener(Platform.OS === 'android' ? 'keyboardDidHide': 'keyboardWillHide', this.keyboardHideListener.bind(this));
}

componentWillUnmount() {
    this.keyboardHideListener.remove()
}

keyboardHideListener 函数中更新 keyboardAvoidingViewKey,每次都应该使用一个新值(我使用了时间戳),并在渲染 KeyboardAvoidingView 元素时使用此键。

keyboardHideListener() {
    this.setState({
        keyboardAvoidingViewKey:'keyboardAvoidingViewKey' + new Date().getTime()
    });
}

render() {
    let { keyboardAvoidingViewKey } = this.state
    return (
        <KeyboardAvoidingView behavior={'height'} key={keyboardAvoidingViewKey} style={...}>
            ...
        </KeyboardAvoidingView>
    )
}

注意:请记住,这将重新创建KeyboardAvoidingView内部的元素(即,将调用它们的constructor函数,我不太确定为什么,我会在进行更深入的研究后更新答案),因此您需要跟踪可能被覆盖的任何状态/属性值。

更新

经过更深入的调查,我现在知道为什么更改键会重新创建视图了。 为了真正理解为什么会发生这种情况,必须熟悉react-native如何将渲染命令分派到本地端,这个特定的解释相当长,如果您感兴趣,可以阅读我的回答here。简而言之,react-native使用Reactjs来区分应该被渲染的变化,然后将这些差异作为命令发送给名为UIManager的组件,UIManager发送命令,将其转换为布局树,根据差异命令更改布局。 一旦在组件上设置了关键字,reactjs就使用此关键字来识别对该组件的更改,如果此关键字更改,则reactjs将该组件视为全新的组件,这又发送了初始命令以创建该组件,使其所有子元素从头开始创建,因为它们被视为新布局树中的新元素,删除旧树并创建新树,而不是仅调整差异。

如果您愿意,您实际上可以通过将以下代码添加到您的App.js文件中来窥探这些分派的消息:

import MessageQueue from 'react-native/Libraries/BatchedBridge/MessageQueue'
const spyFunction = (msg) => {
    console.log(msg);
};

MessageQueue.spy(spyFunction);

如果您这样做,您会注意到在日志中,每次键发生变化时返回的命令是createViews,正如上面所述,它将创建在该组件下嵌套的所有元素。


在我的情况下,键盘就是无法消失,一直弹出和收回。 - Eduard
这可能是另一种问题,你所经历的情况。这段代码不会影响键盘,只会影响隐藏在键盘后面的布局。请仔细阅读问题描述,它说:“当我在应用程序中关闭键盘时,视图的高度没有恢复到原始值。” - Samer Murad
运行得非常好,谢谢! - dsternlicht
2
如果你收到this.setState不是函数的错误,那么在componentDidMount中把this.keyboardHideListener改为this.keyboardHideListener.bind(this) - jinglesthula
谢谢你的回答!帮我省了不少麻烦。顺便提一下,我需要在KeyboardAvoidingView上将key={keyboardAvoidingViewKey}更改为key={this.state.keyboardAvoidingViewKey} - Banjer
显示剩余2条评论

8
请给KeyboardAvoidingView传递一个键,并在键盘打开和关闭时进行更改,以便它可以呈现并占用高度。
<KeyboardAvoidingView behavior="height" style={styles.step} key={values}>

救了我的一天!谢谢! :) - Teuta Koraqi
1
@diofeher,请阅读Samer Murad的回答,他描述了我的回答,你们可以理解。谢谢..!! - Nisarg Thakkar

2

在iOS上使用<KeyboardAvoidingView behavior="padding" style={styles}>来包裹组件,在android上使用<View style={styles}>

“behavior”属性指定键盘避免行为,将其设置为“padding”可确保输入框不被键盘遮挡。记得在样式中设置高度或flex以确保组件正确地布局。

render() {
    const ScrollContainer: View | KeyboardAvoidingView = 
    this.renderDependingOnPlatform();
    const scrollContainerParams: any = {};
    if (isIOS)
        scrollContainerParams.behavior = "padding";
return (
<ScrollContainer style={styles.container} {...scrollContainerParams}>
Scroll and other components
</ScrollContainer>
)}

/**
 * Render scroll container depending on platform
 * @returns {any}
 */
renderDependingOnPlatform() {
    if (isAndroid())
        return View;
    else return KeyboardAvoidingView;
}

0
一个简单的解决方法是将KeyboardAvoidingViewbehavior属性设置为'padding'。这避免了重新调用constructor函数的问题,从而使您可以安全地将信息存储在状态中(比如说您有两个Input,即使用户在点击这两个输入之间折叠键盘,也要将文本的值存储在状态中)。
请注意,此方法可能会略微改变KeyboardAvoidingView子元素的布局。

这对我解决了问题。布局被改变了,但高度偏移来自我的隐藏选项卡栏,所以很容易修复。 - Okikioluwa

0

这是与Samur相同的代码,只不过是用于我的react-native函数组件。

const [keyboardAvoidingViewKey, setKeyboardAvoidingViewKey] = useState(
    'keyboardAvoidingViewKey',
  );

  const keyboardHideListenerCallback = useCallback(() => {
    setKeyboardAvoidingViewKey(
      'keyboardAvoidingViewKey' + new Date().getTime(),
    );
  }, []);

  useEffect(() => {
    const keyboardHideListener = Keyboard.addListener(
      Platform.OS === 'android' ? 'keyboardDidHide' : 'keyboardWillHide',
      keyboardHideListenerCallback,
    );

    return () => {
      keyboardHideListener.remove();
    };
  }, [keyboardHideListenerCallback]);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接