【RN中自定义Android回退行为】
在React-Native项目中为Android的返回键定义自定义的行为,BackAndroid控件已被禁用,所以使用BackHandler控件进行。
简单使用
BackHandler API 用于监听设备上的后退按钮事件,可以调用你自己的函数来处理后退行为。此 API 仅能在 Android 上使用。一般说来,我们为android键添加自定义的响应函数(例如,返回的时候弹出一个警示框告诉你要返回),只要在类中的注册对回退键的监听即可,如下面的代码段所示:
class BaseComponent extends Component<> {
//……
componentDidMount() {
/**
* addEventListener 返回一个 NativeEventSubscription ,可以使用一个参数引用它,然后使用remove去除
* this.back = BackHandler.addEventListener("hardwareBackPress", this.backAction);
* */
BackHandler.addEventListener("hardwareBackPress", this.backAction);
}
componentWillUnmount() {
/* this.back.remove(); */
BackHandler.removeEventListener("hardwareBackPress", this.backAction);
}
//……
}
在函数式组件(即无状态组件中,Hooks)中,定义的代码如下所示:
const App = () => {
//……
useEffect(() => {
BackHandler.addEventListener("hardwareBackPress", backAction);
return () => {
BackHandler.removeEventListener("hardwareBackPress", backAction);
}}, []);
return (
<View></View>
);
};
然后,只要在组件重写backAction方法即可完成自定义的android回退事件响应。
继承
我们在写代码时,不能每一个界面都注册和销毁BackHandler的Listener,所以一般写在BaseComponent中,然后我们实现的界面继承这个Component。
当我们在子控件中重写backAction时,发现它还是使用默认的返回事件,这是为什么呢?
- 原因1:阅读第一节普通调用可以发现:回退键的响应是在componentDidMount中进行的,所以我们必须重写这个注册了监听的生命周期函数并且让它调用super.componentDidMount() 这样,在父组件中注册的监听才能注册在子界面中。同时,别忘了注销监听。
- 原因2:backAciton的事件的监听是通过冒泡的机制进行捕获,返回true时会阻止事件冒泡传递,因而不会执行默认的后退行为,返回false时会使事件继续传递,触发其他注册的监听函数,或是系统默认的后退行为。
- 原因3:如果你打开的界面是一个Modal窗口,那么 BackHandler 不会触发事件。
主界面返回
App是存在返回栈的,所以它在执行的时候不能无限制的执行。
//TODO: 当我们无限制的执行回退会产生什么情况?
在一般的APP中,当我们位于起始界面的时候,点击一下就会弹出“再按一次回退键退出APP”,再快速按一下就会退出app,这是如何操作的呢,如下代码段:
backAction = () => {
const routers = this.props.navigation.getCurrentRoutes();
if (routers.length > 1) {
this.props.navigation.goback();
//this.props.navigation.pop(); 与上一行等价
return true;
}else{
let time = new Date();
this.lastBackPressed = this.thisBackPressed;
this.thisBackPressed = time.getTime();
if (this.lastBackPressed && this.lastBackPressed + 2000 >= this.thisBackPressed) {
//最近2秒内按过back键,可以退出应用。
return false;
}
ToastAndroid.show('再按一次退出应用', ToastAndroid.SHORT);
return true;
}
};
其中,使用getCurrentRoutes().length 只是判断是否是主界面的一种情况,只要你可以判断当前界面到底是不是主界面,任何方法都可以。
参考文档
react-native docs: https://reactnative.cn/docs/backhandler
react native Android返回键监听BackHandler: https://www.cnblogs.com/yulian/p/8676577.html