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

如何使用go_router实现底部导航栏与AppBar的持久化显示?

可以用go_router实现固定AppBar与底部导航栏的路由方案

完全可以通过go_router的嵌套路由/StatefulShellRoute实现需求,核心思路是将固定的AppBar和底部导航栏作为父容器路由的内容,子路由仅替换容器内的页面区域,跳转时父容器不会重建。

核心实现方案:StatefulShellRoute

go_router提供的StatefulShellRoute专门用于处理底部导航栏这类需要持久化状态的场景,它会将父容器(包含AppBar和底部导航)与子路由页面分离,切换子路由或底部导航tab时,父容器始终保持挂载状态。

完整代码示例

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
      title: '固定导航示例',
    );
  }
}

// 定义路由
final GoRouter _router = GoRouter(
  routes: [
    StatefulShellRoute.indexedStack(
      // 父容器:渲染固定的AppBar和底部导航栏
      builder: (context, state, navigationShell) {
        return Scaffold(
          appBar: AppBar(title: const Text('固定导航栏')),
          // 子路由页面会渲染在这个navigationShell中
          body: navigationShell,
          bottomNavigationBar: BottomNavigationBar(
            currentIndex: navigationShell.currentIndex,
            onTap: (index) {
              // 切换底部导航tab
              navigationShell.goBranch(
                index,
                initialLocation: index == navigationShell.currentIndex,
              );
            },
            items: const [
              BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
              BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
            ],
          ),
        );
      },
      // 底部导航对应的路由分支
      branches: [
        // 首页分支
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: '/',
              builder: (context, state) => const HomePage(),
              // 嵌套子路由:从首页跳转的详情页
              routes: [
                GoRoute(
                  path: 'detail',
                  builder: (context, state) => const DetailPage(),
                ),
              ],
            ),
          ],
        ),
        // 设置页分支
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: '/settings',
              builder: (context, state) => const SettingsPage(),
            ),
          ],
        ),
      ],
    ),
  ],
);

// 首页页面
class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        onPressed: () => context.go('/detail'), // 跳转到详情页
        child: const Text('跳转到详情页'),
      ),
    );
  }
}

// 详情页面
class DetailPage extends StatelessWidget {
  const DetailPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text('详情页面'),
          ElevatedButton(
            onPressed: () => context.go('/'), // 返回首页
            child: const Text('返回首页'),
          ),
        ],
      ),
    );
  }
}

// 设置页面
class SettingsPage extends StatelessWidget {
  const SettingsPage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Center(child: Text('设置页面'));
  }
}

效果说明

  • 首页截图:顶部显示固定的"固定导航栏"AppBar,底部有"首页"/"设置"导航项,中间是跳转按钮。
  • 详情页截图:顶部AppBar和底部导航栏完全保留,仅中间区域替换为详情页内容,跳转过程中父容器无重建。

关键细节

  1. StatefulShellRoute.indexedStack使用IndexedStack管理分支页面,会保留每个tab的页面状态(比如首页是StatefulWidget时,输入内容不会因切换tab丢失)。
  2. 子路由跳转(如首页→详情页)仅替换navigationShell的内容,父Scaffold的AppBar和底部导航栏不会触发重建。
  3. 若不需要保留tab状态,也可使用普通ShellRoute,但StatefulShellRoute更贴合底部导航的常用场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:18:44