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

Flutter:如何在ShellRoute中隐藏底部导航栏并支持页面返回?

解决Flutter ShellRoute中特定页面隐藏底部导航栏且支持返回的问题

你的核心问题在于两种路由配置的取舍:嵌套在ShellRoute里的子路由会始终被带导航栏的MainScreen包裹,无法隐藏;拆成全局路由用context.go()会替换整个导航栈,导致无法pop返回。下面给你几个可行的解决方案:

方案一:动态控制ShellRoute中的导航栏显示(推荐)

不需要拆分路由结构,直接在ShellRoute的builder里根据当前路由判断是否隐藏导航栏,保留嵌套路由的层级关系,这样context.pop()可以正常返回。

步骤1:修改ShellRoute的builder

ShellRoute(
  navigatorKey: _shellNavigatorKey,
  builder: (context, state, child) {
    // 根据当前路由路径判断是否需要隐藏导航栏
    final shouldHideNav = state.location.contains(leaveRequestRouteName) || 
                          state.location.contains(switchHolidayRouteName);
    
    return MainScreen(
      child: child,
      showBottomNav: !shouldHideNav, // 传递显示状态给MainScreen
    );
  },
  routes: [
    GoRoute(
      path: '/$dashboardRouteName',
      name: dashboardRouteName,
      pageBuilder: (context, state) => CustomPageRouteBuilder.route(
        key: UniqueKey(),
        child: const DashboardScreen(),
      ),
      routes: [
        GoRoute(
          path: leaveRequestRouteName,
          name: '$dashboardRouteName/$leaveRequestRouteName',
          pageBuilder: (context, state) => CustomPageRouteBuilder.route(
            key: state.pageKey,
            child: const LeaveRequestScreen(),
          ),
        ),
        GoRoute(
          path: switchHolidayRouteName,
          name: '$dashboardRouteName/$switchHolidayRouteName',
          pageBuilder: (context, state) => CustomPageRouteBuilder.route(
            key: state.pageKey,
            child: const SwitchHolidayScreen(),
          ),
        ),
      ],
    ),
  ],
)

步骤2:修改MainScreen接收显示状态

class MainScreen extends StatelessWidget {
  final Widget child;
  final bool showBottomNav;

  const MainScreen({
    super.key,
    required this.child,
    this.showBottomNav = true,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: child,
      // 根据showBottomNav控制导航栏显示
      bottomNavigationBar: showBottomNav ? YourBottomNavigationBar() : null,
    );
  }
}

这样进入leaveRequestRouteName或switchHolidayRouteName页面时,Shell会自动隐藏底部导航栏,返回时又会恢复,且context.pop()完全正常。

方案二:全局路由改用push跳转

如果你坚持用全局路由的结构,把跳转方式从context.go()改成context.push(),这样新页面会被添加到当前导航栈的顶部,而不是替换整个栈,context.pop()就能正常返回上一页。

示例跳转代码:

// 替换原来的context.go('/$leaveRequestRouteName')
context.push('/$leaveRequestRouteName');

这种方式的缺点是全局路由会脱离ShellRoute的管理,后续如果有路由层级相关的逻辑会更难维护。

方案三:使用多ShellRoute拆分路由

把需要隐藏导航栏的页面放在另一个不带底部导航栏的ShellRoute里,不同ShellRoute对应不同的页面容器:

GoRouter(
  routes: [
    // 带底部导航栏的ShellRoute
    ShellRoute(
      navigatorKey: _shellNavigatorKey,
      builder: (context, state, child) => MainScreen(child: child),
      routes: [
        GoRoute(
          path: '/$dashboardRouteName',
          name: dashboardRouteName,
          pageBuilder: (context, state) => CustomPageRouteBuilder.route(
            key: UniqueKey(),
            child: const DashboardScreen(),
          ),
        ),
        // 其他需要显示导航栏的页面
      ],
    ),
    // 不带底部导航栏的ShellRoute
    ShellRoute(
      builder: (context, state, child) => Scaffold(body: child),
      routes: [
        GoRoute(
          path: '/$leaveRequestRouteName',
          name: leaveRequestRouteName,
          pageBuilder: (context, state) => CustomPageRouteBuilder.route(
            key: state.pageKey,
            child: const LeaveRequestScreen(),
          ),
        ),
        GoRoute(
          path: '/$switchHolidayRouteName',
          name: switchHolidayRouteName,
          pageBuilder: (context, state) => CustomPageRouteBuilder.route(
            key: state.pageKey,
            child: const SwitchHolidayScreen(),
          ),
        ),
      ],
    ),
  ],
)

跳转时同样用context.push(),这样既可以隐藏导航栏,也能正常返回。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 11:01:12