背景
- 最近把之前的RN项目更新了,react-native升级到了0.58,react-navigation升级到了3.3.0。
- 我们项目结构是TabNavigation,有A/B/C三个Tab,根据用户的权限来决定展示几个Tab,会有四种情况,ABC、AC、BC、C(C是一直存在的)。用createAppContainer创建了四个TabNavigation
升级
- 按照旧版本的实现,创建三个StackNavigator,按照权限再创建四个TabNavigator,根据权限来决定展示哪个。新版本升级后,统一使用createXXXNavigator生成,然后通过createAppContainer导出才行。
遇到的问题
- 修改为新版本的写法后,发现进入二级页面tabbar不隐藏了,之前的参数不管用了。查阅文档后,官方给出了建议的写法:把TabNavigator当做StackNavigator的一部分,push时二级页面整个盖到TabNavigator上。
- 之前跳转二级页面时写的是this.props.navigation.navigate('XXX'),按照上面官方建议修改之后发现不好使了…原因是this.props.navigation获取到的是当前页面的navigation,但是我们外面包了一层TabNavigator,此时应该用TabNavigator的navigation去navigate('XXX')。比如页面A和页面B,在TabC上,在页面A上navigate('D'),但是页面A的StackNavigator里没有D哇,并且我们要把Tab盖住哇,所以要用TabC的this.props.navigation去navigate('D')才可以。如果页面A的StackNavigator里有D,navigate时tabbar还会在,隐藏不了,就又回到了上一个问题。我的解决办法是:在跳转二级页面时发个通知,用TabC接收,然后再TabC里进行页面跳转。有点笨,但是想不到其它好办法了…
- 还有就是安卓物理返回键的问题。这个问题真的很尴尬啊,在第一个Tab进二级页面,按返回键可以很棒的返回,然而在第二个和第三个Tab进二级页面后,按一下返回没反应,按两下就直接到第一个Tab了!!!Oh my god~~~~然后找解决方案,官方文档给出了,我是想在一个地方写然后全局都可用,来来回试了很多次也没弄好,只能每个页面都写了一次,具体实现看下面的代码。
具体实现
- 我们项目结构是TabNavigation,有A/B/C三个Tab,根据用户的权限来决定展示几个Tab,会有四种情况,ABC、AC、BC、C(C是一直存在的)。用createAppContainer创建了四个TabNavigation
const ABCTabbar = createBottomTabNavigator({ 'ANav': {screen: ANav,}, 'BNav': {screen: BNav,}, 'CNav': {screen: CNav,},});const ACTabbar = createBottomTabNavigator({ 'ANav': {screen: ANav,}, 'CNav': {screen: CNav,},});const BCTabbar = createBottomTabNavigator({ 'BNav': {screen: BNav,}, 'CNav': {screen: CNav,},});const CTabbar = createBottomTabNavigator({ 'CNav': {screen: CNav,},});const ABCTabNavigator = createAppContainer(ABCTabbar);const ACTabNavigator = createAppContainer(ACTabbar);const BCTabNavigator = createAppContainer(BCTabbar);const CTabNavigator = createAppContainer(CTabbar);export { ABCTabNavigator, ACTabNavigator, BCTabNavigator, CTabNavigator };复制代码
- 新建MainNavigation.js,在这个文件里判断用户有哪些权限,然后展示相应的TabNavigator
class MainNav extends Component { render() { if (this.state.permission === 'ABC') { return (); } else if (this.state.permission == 'AC') { return ( ); } else if (this.state.permission == 'BC') { return ( ); } else { return ( ); } }}复制代码
- 在MainNavigation.js里,生成一个MainNavigation,在入口render里配置成就OK了
const Main = createStackNavigator({ MainNav: {screen: MainNav}, DPage: {screen: DPage},});const MainNavigation = createAppContainer(Main);export default MainNavigation;复制代码
- 安卓物理返回键问题。从网上找了个工具类AndroidBackAction.js,修改了一下
import {BackHandler} from 'react-native';const handleAndroidBackButton = callback => { BackHandler.addEventListener('hardwareBackPress', callback);};const removeAndroidBackButtonHandler = (callback) => { BackHandler.removeEventListener('hardwareBackPress', callback);}export {handleAndroidBackButton, removeAndroidBackButtonHandler};复制代码
页面上的实现:
import {handleAndroidBackButton, removeAndroidBackButtonHandler} from '../../Util/AndroidBackAction.js'; // 你自己的路径export default class D extends Component { constructor(props) { super(props); handleAndroidBackButton(this.onBackAndroid); // 一定要在这里写 } componentWillUnmount() { removeAndroidBackButtonHandler(this.onBackAndroid); // 一定要在这里写 } onBackAndroid = () => { this.props.navigation.goBack(); return true; };}复制代码
还有个按两下退出应用的,我是写在了入口的地方(就配置的地方),监听的方式是一样的,就是onBackAndroid实现不一样
onBackAndroid = () => { if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) { //最近2秒内按过back键,可以退出应用。 return false; } this.lastBackPressed = Date.now(); ToastAndroid.show('再按返回退出应用', ToastAndroid.SHORT); return true;};复制代码
好啦,大功告成~~~
结束~撒花~~~