You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Expo Router中实现双TabBar导航?

实现Expo Router双TabBar导航方案

Expo Router 默认的 tabs 目录会生成底部TabBar,但直接嵌套 tabs 目录会引发路由冲突和样式混乱,下面给两种可行的实现思路:

方案一:外层底部TabBar + 内层自定义顶部TabBar

这种方式最直接,外层用Expo Router原生的tabs目录实现底部Tab,在需要顶部Tab的页面内,手动编写顶部Tab切换逻辑,配合路由展示对应内容。

目录结构示例

app/
├── tabs/
│   ├── _layout.tsx       # 底部TabBar配置文件
│   ├── home.tsx          # 底部Tab1:首页(无顶部Tab)
│   └── dashboard/        # 底部Tab2:带顶部Tab的页面
│       ├── _layout.tsx   # 顶部TabBar的布局组件
│       ├── overview.tsx  # 顶部Tab1:概览页
│       └── stats.tsx     # 顶部Tab2:统计页
├── _layout.tsx
└── index.tsx

步骤1:配置底部TabBar(app/tabs/_layout.tsx)

import { Tabs } from 'expo-router';

export default function TabsLayout() {
  return (
    <Tabs
      screenOptions={{
        tabBarActiveTintColor: '#2196F3',
        tabBarInactiveTintColor: '#666',
      }}
    >
      <Tabs.Screen
        name="home"
        options={{ title: '首页' }}
      />
      <Tabs.Screen
        name="dashboard"
        options={{ title: '控制台' }}
      />
    </Tabs>
  );
}

步骤2:实现顶部TabBar(app/tabs/dashboard/_layout.tsx)

不用Expo Router的tabs组件,自定义顶部Tab栏,配合路由切换子页面:

import { View, Pressable, Text, StyleSheet } from 'react-native';
import { Stack, useRouter, usePathname } from 'expo-router';

export default function DashboardLayout() {
  const router = useRouter();
  const pathname = usePathname();

  const isOverviewActive = pathname.includes('overview');
  const isStatsActive = pathname.includes('stats');

  return (
    <View style={{ flex: 1 }}>
      {/* 自定义顶部Tab栏 */}
      <View style={styles.tabContainer}>
        <Pressable
          style={[styles.tabItem, isOverviewActive && styles.activeTab]}
          onPress={() => router.push('/tabs/dashboard/overview')}
        >
          <Text style={[styles.tabText, isOverviewActive && styles.activeText]}>概览</Text>
        </Pressable>
        <Pressable
          style={[styles.tabItem, isStatsActive && styles.activeTab]}
          onPress={() => router.push('/tabs/dashboard/stats')}
        >
          <Text style={[styles.tabText, isStatsActive && styles.activeText]}>统计</Text>
        </Pressable>
      </View>

      {/* 子页面内容区域 */}
      <Stack screenOptions={{ headerShown: false }} />
    </View>
  );
}

const styles = StyleSheet.create({
  tabContainer: {
    flexDirection: 'row',
    backgroundColor: '#fff',
    borderBottomWidth: 1,
    borderBottomColor: '#eee',
  },
  tabItem: {
    flex: 1,
    paddingVertical: 12,
    alignItems: 'center',
  },
  activeTab: {
    borderBottomWidth: 2,
    borderBottomColor: '#2196F3',
  },
  tabText: {
    fontSize: 16,
    color: '#666',
  },
  activeText: {
    color: '#2196F3',
    fontWeight: '500',
  },
});

方案二:全局自定义双层TabBar

如果需要两个TabBar全局共存,可以完全放弃Expo Router的tabs目录,用Stack路由配合自定义双层Tab组件实现。

核心逻辑

  1. 在根布局中根据当前页面路径,决定是否显示顶部TabBar
  2. 自定义底部、顶部Tab组件,通过useRouter跳转页面,usePathname同步激活状态

根布局示例(app/_layout.tsx)

import { View, StyleSheet } from 'react-native';
import { Stack, usePathname } from 'expo-router';
import BottomTabBar from '../components/BottomTabBar';
import TopTabBar from '../components/TopTabBar';

export default function RootLayout() {
  const pathname = usePathname();
  // 判断当前页面是否需要展示顶部TabBar
  const showTopTab = pathname.startsWith('/dashboard');

  return (
    <View style={{ flex: 1 }}>
      <Stack screenOptions={{ headerShown: false }} />
      {showTopTab && <TopTabBar />}
      <BottomTabBar />
    </View>
  );
}

然后分别编写BottomTabBar和TopTabBar组件,逻辑和方案一的自定义Tab一致,通过路由API控制页面切换与状态同步。

注意事项

  • 禁止嵌套Expo Router的tabs目录,避免路由冲突
  • 自定义TabBar时,用usePathname精准判断当前页面,确保激活状态准确
  • 如需切换动画,可配合React Native的Animated组件添加过渡效果

内容的提问来源于stack exchange,提问作者easymoneysnipper35

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 02:05:08