REACT NAVIGATION August 29, 2018

【React Navigation】十二、自定义Android返回键的行为

Words count 4.6k Reading time 4 mins. Read count 0

在默认情况下,当用户点击返回键时,react-navigation将会返回上一级页面,或者直接退出程序(当没有上一级页面时)。这是默认的合理处理,但有些情形下我们可能希望自定义返回键的一些行为。

假如你正在查找一种简单的处理,可以直接导出社区开源的包:react-navigation-backhandler。在接下来的小节中,我们将会介绍这个包是如何实现返回键的自定义功能的

举个例子,在某个页面,用户选择了列表的某一项,选中的那项当前是选中状态。当你按下返回键时,你首先希望的是选中的那项变成不被选中的状态,然后再按一次返回键才是返回上一级页面。以下代码片段说明了这种情况。 我们使用react-native提供的BackHandler,通过订阅导航生命周期来添加自定义hardwareBackPress监听器。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import React from "react";
import { BackHandler } from "react-native";

class ScreenWithCustomBackBehavior extends React.Component {
_didFocusSubscription;
_willBlurSubscription;

constructor(props) {
super(props);
this._didFocusSubscription = props.navigation.addListener('didFocus', payload =>
BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
);
}

componentDidMount() {
this._willBlurSubscription = this.props.navigation.addListener('willBlur', payload =>
BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
);
}

onBackButtonPressAndroid = () => {
if (this.isSelectionModeEnabled()) {
this.disableSelectionMode();
return true;
} else {
return false;
}
};

componentWillUnmount() {
this._didFocusSubscription && this._didFocusSubscription.remove();
this._willBlurSubscription && this._willBlurSubscription.remove();
}

render() {
// ...
}
}

上班提出的方法适用于StackNavigator中显示的屏幕。目前可能不支持在其他情况下自定义后退按钮处理(例如,一个已知情形是:当你希望在一个打开的抽屉导航器上自定义返回键时会不起效)。

为什么我们不使用组件的生命周期回调的函数呢?

  1. 首先,您可能倾向于使用componentDidMount来订阅backpress事件,而使用componentWillUnmount来取消订阅。 我们不使用它们的原因是它们在进入或离开屏幕时通常不被调用。
  2. 更具体地说,考虑这样一个场景:具有屏幕A和B的StackNavigator。导航到A后,调用其componentDidMount。 当按下B时,也会调用其componentDidMount,但A仍然挂载,因此不会调用其componentWillUnmount。
  3. 类似地,当从B返回到A时,会调用B的componentWillUnmount函数,但是A的componentDidMount则不会,因为A一直处在挂载状态。
0%