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

Flutter如何实现跨页面共用appBar与bottomNavigationBar组件

Flutter实现多页面共用AppBar与BottomNavigationBar方案

核心实现逻辑

你需要做一个独立的共用导航父容器页面,这个页面本身是一个完整的Scaffold,自带你抽离的通用appBar和bottomNavigationBar,body区域作为子页面的渲染插槽,和React中Header、Footer中间夹路由的逻辑完全一致。因为你首页需要是欢迎页,只需要把欢迎页和这个父容器作为同级路由配置即可,不需要把父容器套在首页外层。

具体实现步骤

1. 新建共用导航父容器

父容器为StatefulWidget,内部管理底部导航选中状态,支持两种子页面渲染模式:

import 'package:flutter/material.dart';
// 导入你抽离的通用导航组件、各业务子页面
import 'nav_bar.dart';
import 'home_page.dart';
import 'scan_passport.dart';
import 'setting_page.dart';

class MainContainer extends StatefulWidget {
  const MainContainer({super.key});

  @override
  State<MainContainer> createState() => _MainContainerState();
}

class _MainContainerState extends State<MainContainer> {
  int _selectedIndex = 0;
  // 模式1:固定Tab页预加载,适合底部导航对应固定3-5个主页面的场景,切换流畅度最高
  final List<Widget> _tabPages = const [
    HomePage(),
    ScanPassport(),
    SettingPage(),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: navBar(), // 你的通用AppBar组件
      // 模式2:嵌套路由模式,对标React路由插槽,支持body内任意路由跳转
      // 要使用这个模式就注释掉下面的_tabPages引用,替换为这个Navigator组件
      // body: Navigator(
      //   initialRoute: '/home',
      //   onGenerateRoute: (settings) {
      //     Widget currentPage;
      //     switch(settings.name) {
      //       case '/home': currentPage = const HomePage(); break;
      //       case '/scan': currentPage = const ScanPassport(); break;
      //       case '/setting': currentPage = const SettingPage(); break;
      //       default: currentPage = const HomePage();
      //     }
      //     return MaterialPageRoute(builder: (context) => currentPage, settings: settings);
      //   },
      // ),
      body: _tabPages[_selectedIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _selectedIndex,
        onTap: _onItemTapped,
        showSelectedLabels: false,
        showUnselectedLabels: false,
        type: BottomNavigationBarType.fixed,
        // 配置你的底部导航Item
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
          BottomNavigationBarItem(icon: Icon(Icons.document_scanner), label: '扫描'),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
        ],
      ),
    );
  }
}

2. 配置全局路由

在main.dart中配置路由,初始路由设置为欢迎页,主容器作为独立路由存在:

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Demo',
      initialRoute: '/welcome', // 初始加载欢迎页
      routes: {
        '/welcome': (context) => const WelcomePage(), // 你的欢迎页
        '/main': (context) => const MainContainer(), // 共用导航主容器
      },
    );
  }
}

3. 欢迎页跳转逻辑

欢迎页完成引导后,调用路由跳转进入主容器,建议使用pushReplacementNamed禁止用户回退到欢迎页:

// 放在欢迎页的确认/进入按钮点击事件中
Navigator.pushReplacementNamed(context, '/main');

扩展说明

  • 如果需要自定义单个子页面的AppBar内容(比如改标题、加右侧按钮),可以给你抽离的navBar组件加动态配置参数,通过状态管理或者子页面回调同步当前页面的配置即可
  • 如果需要某个子页面隐藏共用导航,只需要在父容器中添加bool类型控制变量,通过状态修改控制appBar和bottomNavigationBar的显隐
  • 使用嵌套路由模式时,子页面内的跳转调用Navigator.of(context)只会操作内部路由栈,不会隐藏外层的共用导航,和你在React中的使用习惯完全一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 03:36:02