本文章的版本是react-navigation 2.5.5
一般来说构建app有两种思路:
方法1:如果我的App 有几个 tab 就需要用 createStackNavigator
建立几个stack,然后用一个createBottomTabNavigator
包裹刚刚创建的几个stack。类似于ios原生
方法2:反过来用stack包裹一个tab和好多screen(单独的页面)
下面分别说说这两种构建:
//首页 详情页
const HomeStack = createStackNavigator({
Home: HomeScreen,
Details: DetailsScreen,
});
//我的 我的设置
const MeStack = createStackNavigator({
Me: MeScreen,
Setting: SettingScreen,
// Details: DetailsScreen 跨tab跳转需要额外注册
});
然后通过 createBottomTabNavigator
把stack包裹
export default createBottomTabNavigator(
{
Home: HomeStack,
Me: MeStack,
});
这种写法有个缺点就是子页面也会存在下面的tab 而且需要在每个stack 判断一下。2.0的处理方法如下:
HomeStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
};
};
如果需要夸tab跳转就额外注册,比如我要从Me 里面跳转到 Details 则需要在 MeStack 里面 设置 Details: DetailsScreen
或者你采用另外一个布局方式 stack包裹tab
const TabOptions = (tabBarTitle, tabBarIconName) => {
const title = tabBarTitle;
const tabBarIcon = (({tintColor,focused})=> {
const color = focused ? CS.THEME11 : CS.COLOR4;
if(title){
return(
<Icon name={tabBarIconName} size={title?FS.ICON_B:40} color={color}/>
)
}else {
return(
<FontAwesome name={tabBarIconName} size={44} color={CS.THEME11}/>
)
}
});
const tabBarVisible = true;
return { title, tabBarIcon, tabBarVisible };
};
const MyTab = createBottomTabNavigator({
ScreenHome: {
screen: ScreenHome,
navigationOptions: ()=> TabOptions('找房', 'oneIcon|icon_search'),
},
ScreenGroup: {
screen: ScreenGroup,
navigationOptions: ()=> TabOptions('圈子', 'oneIcon|icon_fenxiaoquan_light'),
},
ScreenAdd: { screen: ScreenAdd,
// 这里我实现了隐藏单个文字的tab 达到了类似微博的效果我是修改了源码
navigationOptions: ()=> TabOptions('','plus-circle'),
},
ScreenMessage: {
screen: ScreenMessage,
navigationOptions: ()=> TabOptions('消息', 'oneIcon|icon__xiaoxi'),
},
ScreenMe: {
screen: ScreenMe,
navigationOptions: ()=> TabOptions('我的', 'oneIcon|icon_me'),
},
})
const AppStack = createStackNavigator({
MyTab : MyTab,
Detail : Detail
})
但是这种方法也有一个问题 就是tab页面的头不好隐藏,1.0版本的方式不适用了,需要做如下处理
MyTab.navigationOptions = ({ navigation }) => {
let { routeName } = navigation.state.routes[navigation.state.index];
if(routeName=='ScreenHome'||routeName=='ScreenGroup'||routeName=='ScreenMe'){
return {
header:null,
};
}else if(routeName=='ScreenAdd'){
return {
headerTitle:'发布',
};
}else if(routeName=='ScreenMessage'){
return {
headerTitle:'消息',
};
}
};
需要隐藏单个文字的话修改源码如下:
自己额外加了一个判断,文件路径 node_modules/react-navigation-tabs/dist/views
30多行左右
if (typeof label === 'string') {
if(label==''){
return null;
}else {
return <Animated.Text numberOfLines={1} style={[styles.label, { color: tintColor }, showIcon && this._shouldUseHorizontalLabels() ? styles.labelBeside : styles.labelBeneath, styles.labelBeneath, labelStyle]} allowFontScaling={allowFontScaling}>
{label}
</Animated.Text>;
}
}
那么我们的登录流程和怎么和tab结合呢
这个时候我们就要用到createSwitchNavigator
.说白了createSwitchNavigator里面的只能显示一个,这个就相当于之前的reset()
方法.不处理回退操作,切换时将路由重置为默认状态. 他跳转(navigate()
)后其余的页面都销毁了
// 这里演示的是第二种方式
const AppStack = createStackNavigator({
MyTab : MyTab,
Detail : Detail
})
const LoginStack = createStackNavigator({
Login : Login,
Register : Register,
});
export defaul const AppNavigator = createSwitchNavigator({
Splash : Splash, // 这是引导页
LoginStack : LoginStack, // 这里包含登录前的所有页面,比如注册,登录 ,忘记密码 等
App : AppStack, // 这里面包含所有登录后的页面
});