我正在尝试创建一个类似于 Snackbar 的状态消息组件,其签名如下所示:
<StatusMsg
open={this.state.isOpen}
message={this.state.msg}
onRequestClose={someFunc}
/>
当“open”设置为 true 时,消息应该在屏幕上显示动画,在屏幕上停留一段时间,然后再次关闭。
因此,下面的代码可以正常工作,除了在一个相当常见的用例中:当调用组件在旧消息动画关闭屏幕之前设置新消息时。在这种情况下,下面的代码只是替换当前显示的消息并使用相同的计时器。
理想情况下,当添加新消息时,应该首先使旧消息在屏幕外显示动画,然后在新消息中显示动画。(即使新消息文本与旧消息文本相同,我也想确保它这样做。)
我似乎无法弄清楚如何做这样的事情。我最好的猜测是 StatusMsg 实际上应该是一个工厂,用于创建包含消息的动画视图,但我不知道如何使其工作。具体来说,如何使先前的消息在创建新消息时自行关闭。
class StatusMsg extends Component {
state = { exited: false, moveHeightAnimated: new Animated.Value(HIDDEN_HEIGHT) }
timerAutoHide = null;
componentWillMount() {
if (!this.props.open) {
this.setState({ exited: true });
}
}
componentDidMount() {
if (this.props.open) {
this.show();
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.open && this.state.exited) {
this.setState({ exited: false });
}
}
componentDidUpdate(prevProps) {
if (prevProps.open !== this.props.open) {
if (this.props.open) {
this.show();
} else {
clearTimeout(this.timerAutoHide);
}
}
}
componentWillUnmount() {
clearTimeout(this.timerAutoHide);
}
show() {
const toValue = SHOW_HEIGHT;
Animated.timing(this.state.moveHeightAnimated, {
toValue,
duration: 225,
easing: Easing.bezier(0.0, 0.0, 0.2, 1),
}).start(this.setAutoHideTimer);
}
hide() {
const toValue = HIDDEN_HEIGHT;
Animated.timing(this.state.moveHeightAnimated, {
toValue,
duration: 195,
easing: Easing.bezier(0.4, 0.0, 1, 1),
}).start(this.onFinishedHiding);
}
onFinishedHiding = () => {
this.setState({ exited: true });
if (this.props.onRequestClose) {
this.props.onRequestClose();
}
}
setAutoHideTimer = () => {
if (!this.props.onRequestClose) {
return;
}
clearTimeout(this.timerAutoHide);
this.timerAutoHide = setTimeout(() => {
if (!this.props.onRequestClose) {
return;
}
this.hide();
}, this.props.autoHideDuration || DEFAULT_AUTOHIDE_DURATION);
}
render() {
if (!this.props.open && this.state.exited) {
return null;
}
return (
<Animated.View style={[styles.msgContainerStyle, { bottom: this.state.moveHeightAnimated }]} >
<View style={styles.noticeContainerStyle}>
<Text style={styles.msgTextStyle}>{this.props.message}</Text>
</View>
</Animated.View>
);
}
}