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
相关产品推荐
相关产品推荐

