关于Nisarg的回答更详细的解释。
在构造函数中为KeyboardAvoidingView创建一个键
constructor(props) {
this.state = {
keyboardAvoidingViewKey: 'keyboardAvoidingViewKey',
}
}
在键盘的 will/did hide 上添加监听器(并在 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 的组件,该组件发送转换为布局树的命令式命令,它根据差异命令。
一旦你在一个组件上设置了一个键,reactjs 就会使用这个键来识别对所述组件的更改,如果这个键发生了变化,reactjs 会将该组件识别为一个全新的组件,作为回报,它会发送初始命令来创建所述组件,使其成为要从头开始创建子元素,因为在新布局树中被标识为新元素,删除旧树并创建新树,而不仅仅是调整差异
如果您愿意,您实际上可以通过将以下代码添加到您的 App.js 文件中来监视这些发送的消息:
import MessageQueue from 'react-native/Libraries/BatchedBridge/MessageQueue'
const spyFunction = (msg) => {
console.log(msg);
};
MessageQueue.spy(spyFunction);
如果您这样做,您会在日志中注意到每次键更改时,返回的命令是createViews,如上所述,它会创建嵌套在所述组件下的所有元素。