在低版本的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监听即可。为了方便大家参考,我提供这两个页面的完整代码。
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,action,含义如下:
prevNav是之前导航状态,nav是当前导航状态,action是当前进行的操作。所以我们可以通过当前导航的状态中的routes来判断当前界面是否为根界面。
2.下面是WebViewPage的核心代码:
componentDidMount() { if (Platform.OS === 'android') { BackHandler.addEventListener('hardwareBackPress',() => { }); } } onBackAndroid = () => { if (this.state.canGoBack) { this.webView.goBack(); return true; } else { return false; } };
上面这段代码没什么好说的,直接复制粘贴即可。
以上便是自己对react-navigation+BackHandler+webview的集成总结,期待与各位ReactNative开发者交流学习。