Skip to content

底部标签导航(Tab Navigator)

第五部分:路由导航(页面跳转)

底部标签导航(Tab Navigator)是 React Navigation 中常用的导航器类型,用于在应用的不同主要部分之间进行切换。本文将详细介绍 Tab Navigator 的使用方法。

1. 基本使用

安装依赖

首先,需要安装底部标签导航器:

bash
# 使用 npm
npm install @react-navigation/bottom-tabs

# 使用 yarn
yarn add @react-navigation/bottom-tabs

创建标签导航器

jsx
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeScreen from './screens/HomeScreen';
import ProfileScreen from './screens/ProfileScreen';
import SettingsScreen from './screens/SettingsScreen';

const Tab = createBottomTabNavigator();

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

基本配置

jsx
<Tab.Navigator
  screenOptions={{
    tabBarActiveTintColor: '#4CAF50',
    tabBarInactiveTintColor: 'gray',
    tabBarStyle: {
      backgroundColor: '#fff',
      borderTopWidth: 1,
      borderTopColor: '#e0e0e0',
    },
    headerStyle: {
      backgroundColor: '#4CAF50',
    },
    headerTintColor: '#fff',
    headerTitleStyle: {
      fontWeight: 'bold',
    },
  }}
>
  <Tab.Screen name="Home" component={HomeScreen} options={{ title: '首页' }} />
  <Tab.Screen name="Profile" component={ProfileScreen} options={{ title: '个人资料' }} />
  <Tab.Screen name="Settings" component={SettingsScreen} options={{ title: '设置' }} />
</Tab.Navigator>

2. 自定义标签图标

使用内置图标

jsx
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Ionicons } from '@expo/vector-icons';
import HomeScreen from './screens/HomeScreen';
import ProfileScreen from './screens/ProfileScreen';
import SettingsScreen from './screens/SettingsScreen';

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 ? 'home' : 'home-outline';
            } else if (route.name === 'Profile') {
              iconName = focused ? 'person' : 'person-outline';
            } else if (route.name === 'Settings') {
              iconName = focused ? 'settings' : 'settings-outline';
            }

            return <Ionicons name={iconName} size={size} color={color} />;
          },
          tabBarActiveTintColor: '#4CAF50',
          tabBarInactiveTintColor: 'gray',
        })}
      >
        <Tab.Screen name="Home" component={HomeScreen} options={{ title: '首页' }} />
        <Tab.Screen name="Profile" component={ProfileScreen} options={{ title: '个人资料' }} />
        <Tab.Screen name="Settings" component={SettingsScreen} options={{ title: '设置' }} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

使用自定义图标

jsx
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { View, Text, StyleSheet } from 'react-native';
import HomeScreen from './screens/HomeScreen';
import ProfileScreen from './screens/ProfileScreen';
import SettingsScreen from './screens/SettingsScreen';

const Tab = createBottomTabNavigator();

// 自定义图标组件
function HomeIcon({ focused, color, size }) {
  return (
    <View style={[styles.iconContainer, focused && styles.iconContainerFocused]}>
      <Text style={[styles.iconText, { color }]}>🏠</Text>
    </View>
  );
}

function ProfileIcon({ focused, color, size }) {
  return (
    <View style={[styles.iconContainer, focused && styles.iconContainerFocused]}>
      <Text style={[styles.iconText, { color }]}>👤</Text>
    </View>
  );
}

function SettingsIcon({ focused, color, size }) {
  return (
    <View style={[styles.iconContainer, focused && styles.iconContainerFocused]}>
      <Text style={[styles.iconText, { color }]}>⚙️</Text>
    </View>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        screenOptions={{
          tabBarActiveTintColor: '#4CAF50',
          tabBarInactiveTintColor: 'gray',
        }}
      >
        <Tab.Screen 
          name="Home" 
          component={HomeScreen} 
          options={{
            title: '首页',
            tabBarIcon: HomeIcon,
          }}
        />
        <Tab.Screen 
          name="Profile" 
          component={ProfileScreen} 
          options={{
            title: '个人资料',
            tabBarIcon: ProfileIcon,
          }}
        />
        <Tab.Screen 
          name="Settings" 
          component={SettingsScreen} 
          options={{
            title: '设置',
            tabBarIcon: SettingsIcon,
          }}
        />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  iconContainer: {
    padding: 4,
  },
  iconContainerFocused: {
    backgroundColor: 'rgba(76, 175, 80, 0.1)',
    borderRadius: 8,
  },
  iconText: {
    fontSize: 24,
  },
});

3. 高级配置

标签栏样式

jsx
<Tab.Navigator
  screenOptions={{
    tabBarStyle: {
      backgroundColor: '#f8f8f8',
      borderTopWidth: 1,
      borderTopColor: '#e0e0e0',
      paddingBottom: 5,
      paddingTop: 5,
      height: 60,
    },
    tabBarLabelStyle: {
      fontSize: 12,
      marginTop: -5,
    },
    tabBarIconStyle: {
      marginBottom: -5,
    },
  }}
>
  {/* 屏幕配置 */}
</Tab.Navigator>

隐藏标签栏

可以在特定屏幕中隐藏标签栏:

jsx
<Tab.Screen 
  name="Profile" 
  component={ProfileScreen} 
  options={{
    title: '个人资料',
    tabBarStyle: { display: 'none' },
  }}
/>

或者使用 tabBarVisible 选项:

jsx
<Tab.Screen 
  name="Profile" 
  component={ProfileScreen} 
  options={({ route }) => ({
    title: '个人资料',
    tabBarVisible: route.name === 'Profile',
  })}
/>

动态标签栏

可以根据状态动态调整标签栏:

jsx
import React, { useState } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeScreen from './screens/HomeScreen';
import ProfileScreen from './screens/ProfileScreen';
import SettingsScreen from './screens/SettingsScreen';

const Tab = createBottomTabNavigator();

export default function App() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeScreen} options={{ title: '首页' }} />
        {isLoggedIn ? (
          <>
            <Tab.Screen name="Profile" component={ProfileScreen} options={{ title: '个人资料' }} />
            <Tab.Screen name="Settings" component={SettingsScreen} options={{ title: '设置' }} />
          </>
        ) : (
          <Tab.Screen name="Login" component={LoginScreen} options={{ title: '登录' }} />
        )}
      </Tab.Navigator>
    </NavigationContainer>
  );
}

4. 嵌套导航

标签导航器嵌套栈导航器

jsx
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createStackNavigator } from '@react-navigation/stack';
import { Ionicons } from '@expo/vector-icons';
import HomeScreen from './screens/HomeScreen';
import DetailsScreen from './screens/DetailsScreen';
import ProfileScreen from './screens/ProfileScreen';
import EditProfileScreen from './screens/EditProfileScreen';
import SettingsScreen from './screens/SettingsScreen';

const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();

// 首页栈导航
function HomeStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="HomeMain" component={HomeScreen} options={{ title: '首页' }} />
      <Stack.Screen name="Details" component={DetailsScreen} options={{ title: '详情页' }} />
    </Stack.Navigator>
  );
}

// 个人资料栈导航
function ProfileStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="ProfileMain" component={ProfileScreen} options={{ title: '个人资料' }} />
      <Stack.Screen name="EditProfile" component={EditProfileScreen} options={{ title: '编辑资料' }} />
    </Stack.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: ({ focused, color, size }) => {
            let iconName;

            if (route.name === 'Home') {
              iconName = focused ? 'home' : 'home-outline';
            } else if (route.name === 'Profile') {
              iconName = focused ? 'person' : 'person-outline';
            } else if (route.name === 'Settings') {
              iconName = focused ? 'settings' : 'settings-outline';
            }

            return <Ionicons name={iconName} size={size} color={color} />;
          },
          tabBarActiveTintColor: '#4CAF50',
          tabBarInactiveTintColor: 'gray',
        })}
      >
        <Tab.Screen name="Home" component={HomeStack} options={{ headerShown: false, title: '首页' }} />
        <Tab.Screen name="Profile" component={ProfileStack} options={{ headerShown: false, title: '个人资料' }} />
        <Tab.Screen name="Settings" component={SettingsScreen} options={{ title: '设置' }} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

栈导航器嵌套标签导航器

jsx
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from './screens/HomeScreen';
import ProfileScreen from './screens/ProfileScreen';
import SettingsScreen from './screens/SettingsScreen';
import DetailsScreen from './screens/DetailsScreen';

const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();

// 标签导航
function TabNavigator() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} options={{ title: '首页' }} />
      <Tab.Screen name="Profile" component={ProfileScreen} options={{ title: '个人资料' }} />
      <Tab.Screen name="Settings" component={SettingsScreen} options={{ title: '设置' }} />
    </Tab.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Main" component={TabNavigator} options={{ headerShown: false }} />
        <Stack.Screen name="Details" component={DetailsScreen} options={{ title: '详情页' }} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

5. 导航方法

在标签导航中,可以使用以下导航方法:

1. 切换标签

jsx
// 在任意屏幕中
navigation.navigate('Home'); // 切换到首页标签
navigation.navigate('Profile'); // 切换到个人资料标签

2. 重置标签导航

jsx
// 重置整个标签导航
navigation.reset({
  index: 0,
  routes: [{ name: 'Home' }],
});

3. 访问父导航器

在嵌套导航中,可以使用 navigation.getParent() 访问父导航器:

jsx
// 在详情页中
const parentNavigation = navigation.getParent();
if (parentNavigation) {
  parentNavigation.navigate('Profile'); // 切换到个人资料标签
}

6. 常见问题与解决方案

问题 1:标签图标不显示

问题:标签图标不显示或显示不正确。

解决方案

  • 确保安装了正确的图标库(如 @expo/vector-icons
  • 检查图标名称是否正确
  • 确保 tabBarIcon 函数返回有效的 React 元素

问题 2:嵌套导航标题冲突

问题:嵌套导航时,标题显示不正确或冲突。

解决方案

  • 在子导航器中设置 headerShown: false
  • 在父导航器中统一管理标题
  • 使用 options 函数动态设置标题

问题 3:标签栏样式修改失败

问题:无法修改标签栏的样式。

解决方案

  • 使用 tabBarStyle 选项设置标签栏样式
  • 注意平台差异,某些样式在 iOS 和 Android 上可能表现不同
  • 对于复杂的自定义,考虑使用第三方库

问题 4:标签切换动画

问题:标签切换时没有动画或动画不符合预期。

解决方案

  • 使用 animationEnabled 选项启用或禁用动画
  • 使用 swipeEnabled 选项启用或禁用滑动切换

7. 最佳实践

1. 组织导航结构

将导航相关代码组织到单独的文件中:

jsx
// navigation/TabNavigator.js
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Ionicons } from '@expo/vector-icons';
import HomeStack from './HomeStack';
import ProfileStack from './ProfileStack';
import SettingsScreen from '../screens/SettingsScreen';

const Tab = createBottomTabNavigator();

export default function AppTabNavigator() {
  return (
    <Tab.Navigator
      screenOptions={({ route }) => ({
        tabBarIcon: ({ focused, color, size }) => {
          let iconName;

          if (route.name === 'Home') {
            iconName = focused ? 'home' : 'home-outline';
          } else if (route.name === 'Profile') {
            iconName = focused ? 'person' : 'person-outline';
          } else if (route.name === 'Settings') {
            iconName = focused ? 'settings' : 'settings-outline';
          }

          return <Ionicons name={iconName} size={size} color={color} />;
        },
        tabBarActiveTintColor: '#4CAF50',
        tabBarInactiveTintColor: 'gray',
      })}
    >
      <Tab.Screen name="Home" component={HomeStack} options={{ headerShown: false, title: '首页' }} />
      <Tab.Screen name="Profile" component={ProfileStack} options={{ headerShown: false, title: '个人资料' }} />
      <Tab.Screen name="Settings" component={SettingsScreen} options={{ title: '设置' }} />
    </Tab.Navigator>
  );
}

2. 使用类型定义

为导航参数添加类型定义:

typescript
// navigation/types.ts
export type RootTabParamList = {
  Home: undefined;
  Profile: undefined;
  Settings: undefined;
};

export type HomeStackParamList = {
  HomeMain: undefined;
  Details: { id: number; title: string };
};

export type ProfileStackParamList = {
  ProfileMain: undefined;
  EditProfile: undefined;
};

3. 合理使用标签数量

  • 标签数量最好控制在 3-5 个之间
  • 避免使用过多标签,这会导致标签栏拥挤
  • 对于更多的导航项,考虑使用抽屉导航或其他导航模式

4. 优化标签切换性能

  • 对于复杂的标签内容,使用 lazy 选项延迟加载
  • 对于需要保持状态的标签,使用 persistRoute 选项
  • 避免在标签切换时进行 heavy 操作

8. 总结

底部标签导航(Tab Navigator)是 React Navigation 中常用的导航器类型,用于在应用的不同主要部分之间进行切换。通过本文的学习,你应该掌握了以下内容:

  1. Tab Navigator 的基本使用方法
  2. 自定义标签图标的方法
  3. 高级配置选项
  4. 嵌套导航的实现
  5. 导航方法的使用
  6. 常见问题的解决方案
  7. 最佳实践

在实际开发中,合理使用 Tab Navigator,可以创建出直观、易用的应用导航结构,提升用户体验。

© 2026 编程马·菜鸟教程 版权所有