跳至主要内容
版本:6.x

标签导航

在移动应用中最常见的导航方式可能是基于标签的导航。标签可以位于屏幕底部或顶部标题下方(甚至可以代替标题)。

本指南涵盖了 createBottomTabNavigator。您也可以使用 createMaterialBottomTabNavigatorcreateMaterialTopTabNavigator 将标签添加到您的应用程序中。

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

npm install @react-navigation/bottom-tabs

基于标签的导航的最小示例

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

自定义外观

这与您自定义堆栈导航器的方式类似 - 在初始化标签导航器时会设置一些属性,而其他属性可以在 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>
);
}

让我们来分析一下

  • tabBarIcon 是底部标签导航器中支持的选项。因此我们知道可以在屏幕组件的 options 属性中使用它,但在这种情况下,我们选择将其放在 Tab.NavigatorscreenOptions 属性中,以便为了方便集中图标配置。
  • tabBarIcon 是一个函数,它接收 focused 状态、colorsize 参数。如果您进一步查看配置,您将看到 tabBarActiveTintColortabBarInactiveTintColor。这些默认设置为 iOS 平台的默认值,但您可以在此处更改它们。传递给 tabBarIconcolor 是活动或非活动颜色之一,具体取决于 focused 状态(focused 表示活动)。size 是标签栏预期的图标大小。
  • 阅读 完整的 API 参考,以获取有关 createBottomTabNavigator 配置选项的更多信息。

向图标添加徽章

有时我们想向某些图标添加徽章。您可以使用 tabBarBadge 选项 来实现。

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

从 UI 的角度来看,这个组件已经可以使用了,但您仍然需要找到一种方法从其他地方正确传递徽章计数,例如使用 React ContextReduxMobX事件发射器

Tabs with badges

在标签之间跳转

从一个标签切换到另一个标签有一个熟悉的 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>
);
}

每个标签的堆栈导航器

标签通常不只显示一个屏幕 - 例如,在您的 Twitter 提要中,您可以点击一条推文,它会将您带到该标签内的一个新屏幕,其中包含所有回复。您可以将其视为每个标签内都有单独的导航堆栈,这正是我们在 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 或其他组件?

通常会尝试使用独立的标签栏组件,而无需将其集成到您在应用程序中使用的导航库中。在某些情况下,这可以正常工作!但是,您应该注意,这样做可能会遇到一些令人沮丧的意外问题。

例如,React Navigation 的标签导航器负责为您处理 Android 返回按钮,而独立组件通常不这样做。此外,如果您需要调用两个不同的 API 来执行“跳转到此标签,然后转到此屏幕”等操作,那么您(作为开发人员)执行此类操作会更加困难。最后,移动用户界面具有许多小的设计细节,这些细节要求某些组件了解其他组件的布局或存在 - 例如,如果您有一个半透明的标签栏,内容应该在它下面滚动,并且滚动视图应该在底部有一个缩进,等于标签栏的高度,这样您就可以看到所有内容。双击标签栏应该使活动导航堆栈弹出到堆栈顶部,再次执行此操作应该使该堆栈中活动滚动视图滚动到顶部。虽然并非所有这些行为都已在 React Navigation 中开箱即用地实现,但它们将被实现,而如果您使用独立的标签视图组件,您将无法获得任何这些行为。

标签导航器包含一个堆栈,您希望在特定屏幕上隐藏标签栏

请参阅此处文档