Skip to main content
Version: 7.x

自定义 Android 后退按钮行为

默认情况下,当用户按下 Android 硬件后退按钮时,react-navigation 将弹出一个屏幕,如果没有可弹出的屏幕,则退出应用。这是一个合理的默认行为,但在某些情况下你可能想要实现自定义处理。

¥By default, when user presses the Android hardware back button, react-navigation will pop a screen or exit the app if there are no screens to pop. This is a sensible default behavior, but there are situations when you might want to implement custom handling.

例如,考虑一个屏幕,其中用户正在选择列表中的项目,并且 "选择方式" 处于活动状态。按下后退按钮时,你首先希望停用 "选择方式",并且仅在第二次按下后退按钮时才会弹出屏幕。下面的代码片段演示了这种情况。我们利用 react-native 附带的 BackHandler 以及 useFocusEffect 钩子来添加我们自定义的 hardwareBackPress 监听器。

¥As an example, consider a screen where user is selecting items in a list, and a "selection mode" is active. On a back button press, you would first want the "selection mode" to be deactivated, and the screen should be popped only on the second back button press. The following code snippet demonstrates the situation. We make use of BackHandler which comes with react-native, along with the useFocusEffect hook to add our custom hardwareBackPress listener.

onBackPress 返回 true 表示我们已经处理了该事件,react-navigation 的监听器将不会被调用,因此不会弹出屏幕。返回 false 将导致事件冒泡,并且 React 导航的监听器将弹出屏幕。

¥Returning true from onBackPress denotes that we have handled the event, and react-navigation's listener will not get called, thus not popping the screen. Returning false will cause the event to bubble up and react-navigation's listener will pop the screen.

function ScreenWithCustomBackBehavior() {
// ...

useFocusEffect(
React.useCallback(() => {
const onBackPress = () => {
if (isSelectionModeEnabled) {
setIsSelectionModeEnabled(false);
return true;
} else {
return false;
}
};

const subscription = BackHandler.addEventListener(
'hardwareBackPress',
onBackPress
);

return () => subscription.remove();
}, [isSelectionModeEnabled])
);

// ...
}
Try on Snack

所提出的方法对于 StackNavigator 中显示的屏幕非常有效。目前可能不支持其他情况下的自定义后退按钮处理(例如,当你想要在打开的抽屉中处理后退按钮按下时,这不起作用的已知情况。欢迎针对此类用例提出 PR!)。

¥The presented approach will work well for screens that are shown in a StackNavigator. Custom back button handling in other situations may not be supported at the moment (eg. A known case when this does not work is when you want to handle back button press in an open drawer. PRs for such use cases are welcome!).

如果你不想覆盖系统后退按钮,而是希望阻止从屏幕返回,请参阅 防止回去 的文档。

¥If instead of overriding system back button, you'd like to prevent going back from the screen, see docs for preventing going back.

为什么不使用组件生命周期方法

¥Why not use component lifecycle methods

一开始,你可能倾向于使用 componentDidMount 订阅后按事件,使用 componentWillUnmount 取消订阅,或者使用 useEffect 添加监听。这种方法行不通 - 在 导航生命周期 中了解更多相关信息。

¥At first, you may be inclined to use componentDidMount to subscribe for the back press event and componentWillUnmount to unsubscribe, or use useEffect to add the listener. This approach will not work - learn more about this in navigation lifecycle.