Skip to main content
Version: 6.x

标签导航

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

¥Possibly the most common style of navigation in mobile apps is tab-based navigation. This can be tabs on the bottom of the screen or on the top below the header (or even instead of a header).

本指南涵盖 createBottomTabNavigator。你还可以使用 createMaterialBottomTabNavigatorcreateMaterialTopTabNavigator 向你的应用添加选项卡。

¥This guide covers createBottomTabNavigator. You may also use createMaterialBottomTabNavigator and createMaterialTopTabNavigator to add tabs to your application.

在继续之前,首先安装 @react-navigation/bottom-tabs

¥Before continuing, first install @react-navigation/bottom-tabs:

npm install @react-navigation/bottom-tabs

基于选项卡的导航的最小示例

¥Minimal example of tab-based 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();

export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}

Tabs minimal

自定义外观

¥Customizing the appearance

这与自定义堆栈导航器的方式类似 - 有一些属性是在初始化选项卡导航器时设置的,而其他属性可以在 options 中按屏幕自定义。

¥This is similar to how you would customize a stack navigator — there are some properties that are set when you initialize the tab navigator and others that can be customized per-screen in options.

// You can import Ionicons from @expo/vector-icons/Ionicons if you use Expo or
// react-native-vector-icons/Ionicons otherwise.
import Ionicons from 'react-native-vector-icons/Ionicons';

// (...)

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 === 'Settings') {
iconName = focused ? 'ios-list' : 'ios-list-outline';
}

// 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="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}

我们来剖析一下:

¥Let's dissect this:

  • tabBarIcon 是底部选项卡导航器中受支持的选项。所以我们知道我们可以在 options 属性中的屏幕组件上使用它,但在本例中选择将其放在 Tab.NavigatorscreenOptions 属性中,以便集中图标配置以方便使用。

    ¥tabBarIcon is a supported option in bottom tab navigator. So we know we can use it on our screen components in the options prop, but in this case chose to put it in the screenOptions prop of Tab.Navigator in order to centralize the icon configuration for convenience.

  • tabBarIcon 是一个具有 focused 状态、colorsize 参数的函数。如果你进一步查看配置,你将看到 tabBarActiveTintColortabBarInactiveTintColor。这些默认为 iOS 平台默认值,但你可以在此处更改它们。传递到 tabBarIconcolor 要么是活动的,要么是非活动的,具体取决于 focused 状态(聚焦为活动)。size 是选项卡栏期望的图标大小。

    ¥tabBarIcon is a function that is given the focused state, color, and size params. If you take a peek further down in the configuration you will see tabBarActiveTintColor and tabBarInactiveTintColor. These default to the iOS platform defaults, but you can change them here. The color that is passed through to the tabBarIcon is either the active or inactive one, depending on the focused state (focused is active). The size is the size of the icon expected by the tab bar.

  • 有关 createBottomTabNavigator 配置选项的更多信息,请阅读 完整的 API 参考

    ¥Read the full API reference for further information on createBottomTabNavigator configuration options.

向图标添加徽章

¥Add badges to icons

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

¥Sometimes we want to add badges to some icons. You can use the tabBarBadge option to do it:

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

从 UI 角度来看,该组件已可供使用,但你仍然需要找到某种方法从其他地方正确传递徽章计数,例如使用 React 上下文ReduxMobX事件触发器

¥From UI perspective this component is ready to use, but you still need to find some way to pass down the badge count properly from somewhere else, like using React Context, Redux, MobX or event emitters.

Tabs with badges

在选项卡之间跳转

¥Jumping between tabs

从一个选项卡切换到另一个选项卡有一个熟悉的 API — navigation.navigate

¥Switching from one tab to another has a familiar API — navigation.navigate.

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>
);
}

每个选项卡的堆栈导航器

¥A stack navigator for each tab

通常,选项卡不仅仅显示一个屏幕 - 例如,在 Twitter 源上,你可以点击一条推文,它会将你带到该选项卡内的一个新屏幕,其中包含所有回复。你可以将其视为每个选项卡内都有单独的导航堆栈,这正是我们在 React Navigation 中对其进行建模的方式。

¥Often tabs don't just display one screen — for example, on your Twitter feed, you can tap on a tweet and it brings you to a new screen within that tab with all of the replies. You can think of this as there being separate navigation stacks within each tab, and that's exactly how we will model it in React Navigation.

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="HomeStack" component={HomeStackScreen} />
<Tab.Screen name="SettingsStack" component={SettingsStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}

为什么我们需要 TabNavigator 而不是 TabBarIOS 或其他组件?

¥Why do we need a TabNavigator instead of TabBarIOS or some other component?

尝试使用独立的选项卡栏组件而不将其集成到你在应用中使用的导航库中是很常见的。在某些情况下,这效果很好!但是,应该警告你,执行此操作时可能会遇到一些令人沮丧的意外问题。

¥It's common to attempt to use a standalone tab bar component without integrating it into the navigation library you use in your app. In some cases, this works fine! You should be warned, however, that you may run into some frustrating unanticipated issues when doing this.

例如,React Navigation 的选项卡导航器负责为你处理 Android 后退按钮,而独立组件通常不会。此外,如果你需要调用两个不同的 API,那么你(作为开发者)执行诸如 "跳转到此选项卡,然后转到此屏幕" 之类的操作会更加困难。最后,移动用户界面有许多小的设计细节,要求某些组件了解其他组件的布局或存在 - 例如,如果你有一个半透明的选项卡栏,则内容应在其下方滚动,并且滚动视图应有一个插图底部的高度等于选项卡栏的高度,这样你就可以看到所有内容。双击选项卡栏应使活动导航堆栈弹出到堆栈顶部,再次执行此操作应将该堆栈中的活动滚动视图滚动到顶部。虽然并非所有这些行为都是通过 React Navigation 实现的,但如果你使用独立的选项卡视图组件,你将不会得到任何这些行为。

¥For example, React Navigation's tab navigator takes care of handling the Android back button for you, while standalone components typically do not. Additionally, it is more difficult for you (as the developer) to perform actions such as "jump to this tab and then go to this screen" if you need to call into two distinct APIs for it. Lastly, mobile user interfaces have numerous small design details that require that certain components are aware of the layout or presence of other components — for example, if you have a translucent tab bar, content should scroll underneath it and the scroll view should have an inset on the bottom equal to the height of the tab bar so you can see all of the content. Double tapping the tab bar should make the active navigation stack pop to the top of the stack, and doing it again should scroll the active scroll view in that stack scroll to the top. While not all of these behaviors are implemented out of the box yet with React Navigation, they will be and you will not get any of this if you use a standalone tab view component.

选项卡导航器包含一个堆栈,并且你想要隐藏特定屏幕上的选项卡栏

¥A tab navigator contains a stack and you want to hide the tab bar on specific screens

请参阅此处的文档

¥See the documentation here