在低版本的React和react-native开发中,navigator+BackHandler+webiew使用起来比较简单,只需要在第一个页面(LoginPage)和WebViewPage页面注册BackHandler即可,不需求在其他页面注册BackHandler。LoginPage核心代码如下:
componentDidMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this.onBackAndroid);
}
}
componentWillUnmount() {
if (Platform.OS === 'android') {
BackHandler.removeEventListener('hardwareBackPress', () => {
});
}
}
onBackAndroid = () => {
const navigator = this.props.navigator;
const routers = navigator.getCurrentRoutes();
if (routers.length > 2) {
navigator.pop();
return true;//接管默认行为
} else {
//到了主页了
if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
//最近2秒内按过back键,可以退出应用。
BackHandler.exitApp();
return false;
}
this.lastBackPressed = Date.now();
ToastAndroid.show('再按一次退出应用', ToastAndroid.SHORT);
return true;
}
// return false;//默认行为
};
WebViewPage的核心代码如下:
componentDidMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this.onBackAndroid);
}
}
componentWillUnmount() {
if (Platform.OS === 'android') {
BackHandler.removeEventListener('hardwareBackPress', () => {
});
}
}
onBackAndroid = () => {
const navigator = this.props.navigator;
const routers = navigator.getCurrentRoutes();
if (routers.length > 2) {
if (this.state.canGoBack) {
this.webView.goBack();
} else {
navigator.pop();
}
return true;//接管默认行为
} else {
//到了主页了
if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
//最近2秒内按过back键,可以退出应用。
BackHandler.exitApp();
return false;
}
this.lastBackPressed = Date.now();
ToastAndroid.show('再按一次退出应用', ToastAndroid.SHORT);
return true;
}
// return false;//默认行为
};
LoginPage和WebViewPage唯一的不同在于,WebViewPage中多了对webview是否可返回的判断。也可以参考我的另一篇博文
BackHandler是全局的!!!
但是最近因项目的需求,需要用到ReactNavite比较牛B的框架react-navigation,在集成BackHandler时遇到了一些问题:有时点击手机物理返回键无效,有时在关闭webview的时候,会多关闭一个页面。。。总之各种冲突。那么正确的写法应该怎么写呢?
其实也很简单,只需在注册StackNavigator的页面,注册BackHandler监听;还有WebViewPage页面注册BackHandler监听即可。为了方便大家参考,我提供这两个页面的完整代码。
1.首先是注册StackNavigator页面的代码:
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Image,
View,
Text,
ToastAndroid,
BackHandler
} from 'react-native';
import AppNavigator from '../navigators/AppNavigator';
let routes = [];
let lastBackPressed = null;
export default class setup extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.onBackAndroid);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.onBackAndroid);
lastBackPressed = null;
}
onBackAndroid() {
if (routes.length === 1) { // 根界面
if (lastBackPressed && lastBackPressed + 2000 >= Date.now()) {
return false;
}
lastBackPressed = Date.now();
ToastAndroid.show('再按一次退出应用', ToastAndroid.SHORT);
return true;
}
}
render() {
return (
<AppNavigator
onNavigationStateChange={(prevNav, nav, action) => {
routes = nav.routes;
}}/>
);
}
}
上面这段代码,需要说明的是:
a. AppNavigator是注册的StackNavigator;
b. onNavigationStateChange是监听StackNavigator中页面的变化,其中有三个参数prevNav, nav, action,含义如下:
prevNav是之前导航状态,nav是当前导航状态,action是当前进行的操作。所以我们可以通过当前导航的状态中的routes来判断当前界面是否为根界面。
2.下面是WebViewPage的核心代码:
componentDidMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this.onBackAndroid);
}
}
componentWillUnmount() {
if (Platform.OS === 'android') {
BackHandler.removeEventListener('hardwareBackPress', () => {
});
}
}
onBackAndroid = () => {
if (this.state.canGoBack) {
this.webView.goBack();
return true;
} else {
return false;
}
};
上面这段代码没什么好说的,直接复制粘贴即可。
以上便是自己对react-navigation+BackHandler+webview的集成总结,期待与各位ReactNative开发者交流学习。