Skip to content

其他类型的导航

除了上面我们所介绍的 Stack 类型导航以外,React Navigation 中提供了常用的其他类型的导航。本小节我们就一起来看一下这些常用导航类型,主要包括:

Tab navigation#

移动应用程序中最常见的导航样式可能是基于选项卡的导航。这可以是屏幕底部的选项卡,也可以是标题下方顶部的选项卡(甚至可以代替标题)。

首先安装 @react-navigation/bottom-tabs

npm install @react-navigation/bottom-tabs

下面是一个 Tab navigation 最基本的示例:

import * as React from 'react'
import { Text, View } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
)
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
)
}
const Tab = createBottomTabNavigator()
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
)
}
export default function App() {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
)
}

我们同样可以自定义外观,这类似于之前所介绍的 Stack 路由的方式,在初始化选项卡导航器时会设置一些属性,而其他属性可以在选项中按屏幕自定义。

// You can import Ionicons from @expo/vector-icons if you use Expo or
// react-native-vector-icons/Ionicons otherwise.
import * as React from 'react'
import { Text, View } from 'react-native'
import { Ionicons } from '@expo/vector-icons'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import { NavigationContainer } from '@react-navigation/native'
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
)
}
function MailScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
)
}
const Tab = createBottomTabNavigator()
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName
if (route.name === 'Home') {
iconName = focused
? 'ios-information-circle'
: 'ios-information-circle-outline'
} else if (route.name === 'Mail') {
iconName = focused ? 'ios-mail' : 'ios-mail-unread'
}
// You can return any component that you like here!
return <Ionicons name={iconName} size={size} color={color} />
},
tabBarActiveTintColor: 'tomato',
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Mail" component={MailScreen} />
</Tab.Navigator>
</NavigationContainer>
)
}

在上面的示例中,我们用到了 tabBarIcon 属性,该属性是底部选项卡导航器中支持的选项,需要将它放在 Tab.Navigator 的 screenOptions 属性中是为了方便集中图标配置。tabBarIcon 是一个函数,它被赋予了焦点状态、颜色和大小参数。另外,tabBarActiveTintColortabBarInactiveTintColor 表示活动以及非活动的颜色值。

有时我们想给一些图标添加徽章。可以使用 tabBarBadge 选项来执行此操作:

<Tab.Screen name="Mail" component={MailScreen} options={{ tabBarBadge: 3 }} />

当我们处于某一屏中,想要通过屏幕中的按钮进行 Tab 跳转可以使用 navigation.navigate

import * as React from 'react'
import { Button, Text, View } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
<Button
title="Go to Settings"
onPress={() => navigation.navigate('Settings')}
/>
</View>
)
}
function SettingsScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
</View>
)
}
const Tab = createBottomTabNavigator()
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
)
}

很多时候,我们的某一屏并不是只属于某一个 Tab 栏,而是有多个 Tab 栏都可以跳转到这一屏,下面是一个这种情况的示例:

import * as React from 'react'
import { Button, Text, View } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
function DetailsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Details!</Text>
</View>
)
}
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
)
}
function SettingsScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
)
}
const HomeStack = createNativeStackNavigator()
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
)
}
const SettingsStack = createNativeStackNavigator()
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Details" component={DetailsScreen} />
</SettingsStack.Navigator>
)
}
const Tab = createBottomTabNavigator()
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsStackScreen} />
</Tab.Navigator>
</NavigationContainer>
)
}

更多关于 Tab navigation 标签页导航的 API,可以参阅 https://reactnavigation.org/docs/bottom-tab-navigator#api-definition

Drawer navigation#

Drawer navigation 翻译成中文叫做抽屉导航,其实就是导航中常见的使用左侧(有时是右侧)的抽屉在屏幕之间导航。

首先第一步还是需要安装该类型的导航:

npm i @react-navigation/drawer

除了安装 @react-navigation/drawer 依赖库以外,这种类型的导航还需要额外安装 react-native-gesture-handler 以及 react-native-reanimated 依赖库,然后将下面的:

import 'react-native-gesture-handler'

放在入口文件的最上面,并且在 babel.config.js 中添加 plugins,具体操作如下图:

image-20220624101324768

具体安装步骤请参阅:https://reactnavigation.org/docs/drawer-navigator#installation

下面是一个关于抽屉导航的简单示例:

import 'react-native-gesture-handler'
import * as React from 'react'
import { Button, View } from 'react-native'
import { createDrawerNavigator } from '@react-navigation/drawer'
import { NavigationContainer } from '@react-navigation/native'
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
onPress={() => navigation.navigate('Notifications')}
title="Go to notifications"
/>
</View>
)
}
function NotificationsScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigation.goBack()} title="Go back home" />
</View>
)
}
const Drawer = createDrawerNavigator()
export default function App() {
return (
<NavigationContainer>
<Drawer.Navigator useLegacyImplementation initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Notifications" component={NotificationsScreen} />
</Drawer.Navigator>
</NavigationContainer>
)
}

注:添加 Babel 插件后,重新启动开发服务器并清除捆绑程序缓存:expo start —clear

可以通过 openclose 方法来打开或者关闭抽屉,通过 toggleDrawer 来切换抽屉。

示例如下:

import * as React from 'react'
import { View, Text, Button } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from '@react-navigation/drawer'
function Feed({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Feed Screen</Text>
<Button title="Open drawer" onPress={() => navigation.openDrawer()} />
<Button title="Toggle drawer" onPress={() => navigation.toggleDrawer()} />
</View>
)
}
function Notifications() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Notifications Screen</Text>
</View>
)
}
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem
label="Close drawer"
onPress={() => props.navigation.closeDrawer()}
/>
<DrawerItem
label="Toggle drawer"
onPress={() => props.navigation.toggleDrawer()}
/>
</DrawerContentScrollView>
)
}
const Drawer = createDrawerNavigator()
function MyDrawer() {
return (
<Drawer.Navigator
useLegacyImplementation
drawerContent={(props) => <CustomDrawerContent {...props} />}
>
<Drawer.Screen name="Feed" component={Feed} />
<Drawer.Screen name="Notifications" component={Notifications} />
</Drawer.Navigator>
)
}
export default function App() {
return (
<NavigationContainer>
<MyDrawer />
</NavigationContainer>
)
}

更多关于 Drawer navigation 抽屉导航的 API,可以参阅 https://reactnavigation.org/docs/drawer-navigator#api-definition

Material Top Tabs Navigator#

Material Top Tabs Navigator 翻译成中文叫做“顶部滑动选项卡导航”。要使用这种导航,首先还是需要先安装依赖,命令如下:

npm install @react-navigation/material-top-tabs react-native-tab-view

除了上面的依赖以外,还需要安装 react-native-pager-view。因为我们是使用 expo 搭建的项目,因此安装指令如下:

expo install react-native-pager-view

到这里,依赖安装就完毕了,下面是一个这种导航的简单示例:

import * as React from 'react'
import { Text, View } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs'
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
)
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
)
}
const Tab = createMaterialTopTabNavigator()
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
)
}

更多关于 Material Top Tabs Navigator 顶部滑动选项卡导航的 API,可以参阅 https://reactnavigation.org/docs/material-top-tab-navigator#api-definition