关于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
,正如上面所述,它将创建在该组件下嵌套的所有元素。
this.setState
不是函数的错误,那么在componentDidMount
中把this.keyboardHideListener
改为this.keyboardHideListener.bind(this)
。 - jinglesthulakey={keyboardAvoidingViewKey}
更改为key={this.state.keyboardAvoidingViewKey}
。 - Banjer<KeyboardAvoidingView behavior="height" style={styles.step} key={values}>
在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;
}
KeyboardAvoidingView
的behavior
属性设置为'padding'。这避免了重新调用constructor
函数的问题,从而使您可以安全地将信息存储在状态中(比如说您有两个Input
,即使用户在点击这两个输入之间折叠键盘,也要将文本的值存储在状态中)。KeyboardAvoidingView
子元素的布局。这是与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]);