Skip to content

Navigation

Flutter 提供多种导航组件:BottomNavigationBar(底部导航栏)、TabBar(标签栏)、Navigator(页面路由)。

构造函数

BottomNavigationBar

dart
BottomNavigationBar({
  Key? key,                                                        // 组件标识
  required List<BottomNavigationBarItem> items,                     // 导航项列表(必填,2~5 个)
  ValueChanged<int>? onItemSelected,                              // 选中项变化回调(旧 API)
  ValueChanged<int>? onTap,                                       // 点击回调(推荐)
  int currentIndex = 0,                                           // 当前选中索引
  double? elevation,                                              // 阴影高度
  Color? backgroundColor,                                        // 背景色
  Color? selectedItemColor,                                      // 选中项颜色(图标+文字)
  Color? unselectedItemColor,                                    // 未选中项颜色
  IconThemeData? selectedIconTheme,                              // 选中图标主题
  IconThemeData? unselectedIconTheme,                            // 未选中图标主题
  double selectedFontSize = 14,                                  // 选中文字大小
  double unselectedFontSize = 12,                                // 未选中文字大小
  TextStyle? selectedLabelStyle,                                  // 选中标签样式
  TextStyle? unselectedLabelStyle,                                // 未选中标签样式
  bool showSelectedLabels = true,                                 // 是否显示选中标签
  bool showUnselectedLabels = true,                               // 是否显示未选中标签
  BottomNavigationBarType? type,                                 // 导航栏类型
  double? iconSize,                                              // 图标大小
  double? selectedIconSize,                                      // 选中图标大小
  double? mouseCursor,                                           // 鼠标指针
  LandscapeLayout? landscapeLayout,                               // 横屏布局
  bool enableFeedback = true,                                     // 触觉反馈
})

BottomNavigationBarItem

dart
BottomNavigationBarItem({
  required Widget icon,                                            // 图标(必填)
  Widget? activeIcon,                                              // 选中状态图标
  String? label,                                                  // 标签文字
  String? tooltip,                                                // 长按提示
  Color? backgroundColor,                                        // 背景色(Shifting 模式用)
})
dart
NavigationBar({                                                    // M3 底部导航栏
  Key? key,
  required List<NavigationDestination> destinations,               // 导航项(必填)
  int selectedIndex = 0,                                          // 当前索引
  ValueChanged<int>? onDestinationSelected,                       // 选中回调
  double? elevation,                                              // 阴影高度
  Color? backgroundColor,                                        // 背景色
  double? height,                                                 // 高度
  AnimationDuration? animationDuration,                           // 动画时长
  LabelBehavior? labelBehavior,                                   // 标签显示行为
})
dart
NavigationDestination({
  required Widget icon,                                            // 图标
  Widget? selectedIcon,                                           // 选中图标
  required String label,                                          // 标签文字(必填)
  String? tooltip,                                                // 长按提示
})

TabBar

dart
TabBar({
  Key? key,
  required List<Tab> tabs,                                        // Tab 列表(必填)
  TabController? controller,                                     // 控制器
  bool isScrollable = false,                                      // 是否可滚动(标签多时设为 true)
  EdgeInsetsGeometry? padding,                                   // 内边距
  Color? indicatorColor,                                         // 指示器颜色
  bool automaticIndicatorColorAdjustment = true,                 // 自动调整指示器颜色
  double? indicatorWeight,                                      // 指示器高度(默认 2)
  EdgeInsetsGeometry? indicatorPadding,                         // 指示器内边距
  Decoration? indicator,                                         // 自定义指示器
  TabBarIndicatorSize? indicatorSize,                            // 指示器大小模式
  Color? labelColor,                                            // 选中标签颜色
  Color? unselectedLabelColor,                                  // 未选中标签颜色
  TextStyle? labelStyle,                                        // 选中标签样式
  TextStyle? unselectedLabelStyle,                             // 未选中标签样式
  MaterialTapTargetSize? materialTapTargetSize,
  DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  MouseCursor? mouseCursor,
  bool? enableFeedback,
  ValueChanged<int>? onTap,                                     // 点击回调
  double? overlayColor,
})

Tab

dart
Tab({
  Key? key,
  String? text,                                                   // 标签文字(与 icon 二选一)
  Widget? icon,                                                   // 标签图标
  EdgeInsetsGeometry? iconMargin,                                // 图标间距
  double? height,                                                // 高度
  Widget? child,                                                  // 自定义子组件
})

TabBarView

dart
TabBarView({
  Key? key,
  required List<Widget> children,                                 // 页面列表(必填)
  TabController? controller,                                     // 控制器
  ScrollPhysics? physics,                                        // 滚动物理效果
  DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  double? viewportFraction = 1.0,                               // 视口占比
})

TabController

dart
TabController({
  required int length,                                             // Tab 数量(必填)
  TickerProvider? vsync,                                         // Ticker 提供者(必填,通常用 SingleTickerProviderStateMixin)
  int initialIndex = 0,                                          // 初始索引
  Duration? animationDuration,                                   // 动画时长
})

TabController 属性/方法

属性/方法类型说明
indexint当前选中索引
animationAnimation<double>动画对象
lengthintTab 数量
animateTo(index)void动画切换到指定 Tab
offsetdouble拖拽偏移量
dispose()void释放资源

属性速查

BottomNavigationBar 属性速查

属性类型默认值说明
itemsList<BottomNavigationBarItem>必填导航项(2~5 个)
currentIndexint0当前选中索引
onTapValueChanged<int>?null点击回调
typeBottomNavigationBarType?自动导航栏类型
selectedItemColorColor?主题色选中颜色
unselectedItemColorColor?灰色未选中颜色
showSelectedLabelsbooltrue显示选中标签
showUnselectedLabelsbooltrue显示未选中标签
backgroundColorColor?白色背景色
elevationdouble?8阴影高度

BottomNavigationBarType 速查

说明
BottomNavigationBarType.fixed固定模式:所有项等宽,适合 3~4 项
BottomNavigationBarType.shifting移动模式:选中项更宽,背景色变化,适合 5 项

TabBar 属性速查

属性类型默认值说明
tabsList<Tab>必填Tab 列表
controllerTabController?null控制器
isScrollableboolfalse标签多时设为 true
indicatorColorColor?主题色指示器颜色
indicatorWeightdouble?2指示器高度
labelColorColor?主题色选中标签颜色
unselectedLabelColorColor?灰色未选中标签颜色
onTapValueChanged<int>?null点击回调
特性BottomNavigationBarNavigationBar (M3)
Material 版本Material 2Material 3
最大项数5无限制(建议 3~5)
选中效果颜色变化背景药丸 + 颜色变化
指示器药丸形背景
推荐度旧项目✅ 新项目推荐

基本路由操作

dart
// 跳转新页面
Navigator.push(context, MaterialPageRoute(builder: (context) => SecondPage()));

// 返回上一页
Navigator.pop(context);

// 带返回值的跳转
final result = await Navigator.push(context, MaterialPageRoute(builder: (_) => SecondPage()));
Navigator.pop(context, '返回值');

// 替换当前页面
Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => LoginPage()));

// 清空栈并跳转(用于退出登录)
Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(builder: (_) => LoginPage()),
  (route) => false,            // 清空所有路由
);

// 返回到指定页面
Navigator.popUntil(context, ModalRoute.withName('/home'));

// 返回根页面
Navigator.popUntil(context, (route) => route.isFirst);

命名路由

dart
// MaterialApp 中注册路由
MaterialApp(
  initialRoute: '/',
  routes: {
    '/': (context) => HomePage(),
    '/detail': (context) => DetailPage(),
    '/settings': (context) => SettingsPage(),
  },
)

// 跳转命名路由
Navigator.pushNamed(context, '/detail');

// 带参数跳转
Navigator.pushNamed(context, '/detail', arguments: {'id': 123});

// 在目标页面获取参数
final args = ModalRoute.of(context)!.settings.arguments as Map;

快速示例

底部导航栏

dart
int currentIndex = 0;

Scaffold(
  body: IndexedStack(                           // 保持页面状态
    index: currentIndex,
    children: [
      HomePage(),
      SearchPage(),
      ProfilePage(),
    ],
  ),
  bottomNavigationBar: BottomNavigationBar(
    currentIndex: currentIndex,
    onTap: (index) => setState(() => currentIndex = index),
    selectedItemColor: Colors.blue,
    items: [
      BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
      BottomNavigationBarItem(icon: Icon(Icons.search), label: '搜索'),
      BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'),
    ],
  ),
)

M3 NavigationBar

dart
int currentIndex = 0;

Scaffold(
  body: IndexedStack(
    index: currentIndex,
    children: [HomePage(), SearchPage(), ProfilePage()],
  ),
  bottomNavigationBar: NavigationBar(
    selectedIndex: currentIndex,
    onDestinationSelected: (index) => setState(() => currentIndex = index),
    destinations: [
      NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: '首页'),
      NavigationDestination(icon: Icon(Icons.search), label: '搜索'),
      NavigationDestination(icon: Icon(Icons.person_outline), selectedIcon: Icon(Icons.person), label: '我的'),
    ],
  ),
)

TabBar(使用 DefaultTabController)

dart
DefaultTabController(
  length: 3,
  child: Scaffold(
    appBar: AppBar(
      title: Text('Tab 示例'),
      bottom: TabBar(
        tabs: [
          Tab(text: '最新'),
          Tab(text: '热门'),
          Tab(text: '推荐'),
        ],
      ),
    ),
    body: TabBarView(
      children: [
        LatestPage(),
        HotPage(),
        RecommendPage(),
      ],
    ),
  ),
)

TabBar(手动控制)

dart
class _MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
  late TabController tabController;

  @override
  void initState() {
    super.initState();
    tabController = TabController(length: 3, vsync: this);
  }

  @override
  void dispose() {
    tabController.dispose();       // 必须释放
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('手动控制 Tab'),
        bottom: TabBar(
          controller: tabController,
          tabs: [Tab(text: 'A'), Tab(text: 'B'), Tab(text: 'C')],
        ),
      ),
      body: TabBarView(
        controller: tabController,
        children: [PageA(), PageB(), PageC()],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 编程式切换 Tab
          tabController.animateTo((tabController.index + 1) % 3);
        },
        child: Icon(Icons.swap_horiz),
      ),
    );
  }
}

页面跳转并接收返回值

dart
// 跳转
final result = await Navigator.push<String>(
  context,
  MaterialPageRoute(builder: (_) => EditPage()),
);
if (result != null) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('保存成功: $result')),
  );
}

// 目标页面返回值
Navigator.pop(context, '已保存');

常见错误

1. BottomNavigationBar 超过 5 个项

dart
// ❌ 错误:超过 5 项会报错
BottomNavigationBar(items: [/* 6 个项 */])

// ✅ 修复:使用 NavigationBar 或重新设计
NavigationBar(destinations: [/* 可以超过 5 个 */])

2. TabBar 和 TabBarView 的 controller 不一致

dart
// ❌ 错误:TabBar 和 TabBarView 用不同的 controller
TabBar(controller: ctrl1, ...)
TabBarView(controller: ctrl2, ...)    // 不联动!

// ✅ 修复:使用同一个 controller,或都用 DefaultTabController

3. IndexedStack vs 切换 Widget

dart
// ❌ 问题:直接切换 Widget 会丢失页面状态
body: pages[currentIndex],         // 切换时重建

// ✅ 修复:使用 IndexedStack 保持状态
body: IndexedStack(
  index: currentIndex,
  children: [Page1(), Page2(), Page3()],   // 同时存在,只显示一个
)
// 注意:所有页面都会被构建,如果页面很重可能影响性能

4. TabController 未 dispose

dart
// ✅ 必须在 dispose 中释放
@override
void dispose() {
  tabController.dispose();
  super.dispose();
}

基于 Flutter 官方文档整理