React-native Stack 和 TabBottom 和 Drawer的 导航嵌套使用
说实话 RN 的文档,我表示看的很吃力
此文章为ReactNavigation导航库5.0版本的第4篇,前几篇系列文章如下:
React Navigation5.0系列一:StackNavigator的使用
React Navigation5.0系列二:TabNavigation的使用
React Navigation5.0系列三:Drawer navigation的使用
此前几篇系列文章,主要讲了StackNavigator, TavNavigation以及Drawer Navigation的使用讲解,现实中往往是不同的导航组件组合进行使用的,本篇文章主要讲解导航的嵌套使用及注意事项。
创建需要的页面
// 设置页面 const SettingsScreen = ({ navigation }) => { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>SettingScreen</Text> <Button title="Go to Details" onPress={() => navigation.navigate('Detail')} /> </View> ) } // 首页 const HomeScreen = ({ navigation }) => { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>HomeScreen</Text> <Button title="Go to Details" onPress={() => navigation.navigate('Detail')} /> </View> ) } // 详情页 const DetailScreen = ({ navigation }) => { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>DetailScreen</Text> <Button title="Go to Detail Again" // onPress={() => navigation.navigate('Detail')} onPress={() => navigation.push('Detail')} /> <Button title="Go to Home" onPress={() => navigation.navigate('Home')} /> <Button title="Go back" onPress={() => navigation.goBack()} /> <Button title="Go back to first screen in stack" onPress={() => navigation.popToTop()} /> </View> ) }
创建三个对应的导航器实例
const Tab = createBottomTabNavigator(); // 选项卡页签tab navigator 实例 const RootStack = createStackNavigator(); // 堆栈stack 实例 const Drawer = createDrawerNavigator(); // 抽屉drawer实例
创建底部导航路由,采用系列二文章代码
function IconWithBadge({ icon, badgeCount, size }) { return ( <View style={{ width: 24, height: 24, margin: 5 }}> <Image source={icon} style={{ width: size, height: size }} /> {badgeCount > 0 && ( <View style={{ // On React Native < 0.57 overflow outside of parent will not work on Android, see https://git.io/fhLJ8 position: 'absolute', right: -6, top: -3, backgroundColor: 'red', borderRadius: 6, width: 12, height: 12, justifyContent: 'center', alignItems: 'center', }} > <Text style={{ color: 'white', fontSize: 10, fontWeight: 'bold' }}> {badgeCount} </Text> </View> )} </View> ); } function HomeIconWithBadge(props) { // You should pass down the badgeCount in some other ways like React Context API, Redux, MobX or event emitters. return <IconWithBadge {...props} badgeCount={3} />; } const TabScreen = () => { return ( <Tab.Navigator headerMode='none' screenOptions={({ route }) => ({ tabBarIcon: ({ focused, color, size }) => { if (route.name === 'Home') { return ( <HomeIconWithBadge icon={ focused ? HomeIconActive : HomeIconNormal } size={size} color={color} /> ); } else if (route.name === 'Settings') { return ( <Image source={focused ? WorkIconActive : WorkIconNormal} style={{width: size, height: size}} /> ); } }, })} tabBarOptions={{ activeTintColor: 'tomato', inactiveTintColor: 'gray', }} > <Tab.Screen name="Home" component={HomeScreen} /> <Tab.Screen name="Settings" component={SettingsScreen} /> </Tab.Navigator> ) }
堆栈(Stack)与Tab嵌套
const rootRouteScreen = () => { return (<RootStack.Navigator initialRouteName={'TabNav'}> <RootStack.Screen name='TabNav' component={TabScreen} /> <RootStack.Screen name="Detail" component={DetailScreen} /> </RootStack.Navigator> ) }
Stack Navigator, Tab Navigator与Drawer Navigator综合嵌套
const App = () => { return ( <NavigationContainer> <Drawer.Navigator initialRouteName="Home" drawerType='slide' drawerContent={(props) => <CustomDrawerContent {...props} />} > <Drawer.Screen name='root' component={rootRouteScreen} /> <Drawer.Screen name='Setting' component={SettingsScreen} /> </Drawer.Navigator> </NavigationContainer> ); }
最后我们来看一下效果
嵌套导航的最佳实践
建议将嵌套做到最少,应该尝试采用尽可能少的嵌套来实现你的业务需求,因为多层嵌套会导致如下几个问题:
- 在多层嵌套的页面,代码难以维护
- 深度嵌套的视图层次结构,这可能会导致低端设备的内存和性能问题
- 嵌套相同类型的导航器(例如,选项卡内的选项卡,抽屉内的抽屉等)让用户的体验极差。