背景
- 最近把之前的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上。reactnavigation.org/docs/en/nav…
- 之前跳转二级页面时写的是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~~~~然后找解决方案,官方文档给出了reactnavigation.org/docs/en/cus…,我是想在一个地方写然后全局都可用,来来回试了很多次也没弄好,只能每个页面都写了一次,具体实现看下面的代码。
具体实现
- 我们项目结构是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 (<ABCTabNavigator/>);
} else if (this.state.permission == 'AC') {
return (<ACTabNavigator/>);
} else if (this.state.permission == 'BC') {
return (<BCTabNavigator/>);
} else {
return (<CTabNavigator/>);
}
}
}
复制代码
- 在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;
};
复制代码
好啦,大功告成~~~
结束~撒花~~~