Flutter Go Router导航配置求助:启动闪屏与Shell路由需求
解决方案
一、核心问题分析
当前代码的主要问题:
- 闪屏页未显示:用户打开任意路径时,GoRouter直接匹配对应子路由,不会触发根路径的闪屏页
- 莫名跳转:闪屏页硬编码跳转至
/catalogue,未保留用户原始访问路径 - 导航失效:未正确使用
ShellRoute,路由嵌套逻辑混乱
二、分步实现需求
1. 首次打开任意路径显示闪屏页(仅一次)
使用GoRouter的redirect功能结合状态管理,统一处理首次进入逻辑:
首先在MenuProvider中添加状态标记:
class MenuProvider extends ChangeNotifier { bool _hasShownSplash = false; String? _initialPath; bool get hasShownSplash => _hasShownSplash; String? get initialPath => _initialPath; void markSplashShown() { _hasShownSplash = true; notifyListeners(); } void saveInitialPath(String path) { _initialPath = path; notifyListeners(); } }
修改GoRouter配置,添加重定向规则:
final _navigatorKey = GlobalKey<NavigatorState>(); routerConfig: GoRouter( navigatorKey: _navigatorKey, redirect: (context, state) { final menuProvider = Provider.of<MenuProvider>(context, listen: false); final currentPath = state.uri.toString(); // 首次进入且不在闪屏页,记录原始路径并跳转至闪屏 if (!menuProvider.hasShownSplash && currentPath != '/splash') { menuProvider.saveInitialPath(currentPath); return '/splash'; } // 闪屏已显示且当前在闪屏页,跳转至原始路径(默认/catalogue) if (menuProvider.hasShownSplash && currentPath == '/splash') { return menuProvider.initialPath ?? '/catalogue'; } return null; // 正常导航 }, routes: [ // 闪屏页路由 GoRoute( path: '/splash', name: 'splash', builder: (context, state) { return SplashScreenLogoV5( onComplete: () { Provider.of<MenuProvider>(context, listen: false).markSplashShown(); }, ); }, ), // 闪屏后启用的Shell路由 ShellRoute( builder: (context, state, child) { // 这里是你的全局Shell布局(比如带导航栏的容器) return Scaffold( body: child, bottomNavigationBar: BottomNavigationBar( // 你的底部导航逻辑 ), ); }, routes: [ GoRoute( path: '/catalogue', name: 'catalogue', builder: (context, state) => const HomePage(), routes: [ GoRoute( name: 'home', path: 'home', builder: (context, state) => const HomePage(), ), GoRoute( name: 'portfolio', path: 'portfolio', builder: (context, state) => const HomePage(startPage: 1), ), GoRoute( name: 'price', path: 'price', builder: (context, state) => const HomePage(startPage: 2), ), GoRoute( name: 'contacts', path: 'contacts', builder: (context, state) => const HomePage(startPage: 3), ), ], ), ], ), ], ),
修改闪屏页,移除硬编码跳转,改为回调通知完成:
class SplashScreenLogoV5 extends StatefulWidget { final VoidCallback onComplete; const SplashScreenLogoV5({Key? key, required this.onComplete}) : super(key: key); @override State<SplashScreenLogoV5> createState() => _SplashScreenLogoV5State(); } class _SplashScreenLogoV5State extends State<SplashScreenLogoV5> { @override void initState() { super.initState(); // 模拟闪屏时长 Future.delayed(const Duration(seconds: 2), widget.onComplete); } @override Widget build(BuildContext context) { return const Scaffold( body: Center(child: Text('Splash Screen')), ); } }
2. 禁用浏览器返回按钮导航
在ShellRoute的布局中添加WillPopScope拦截返回事件:
ShellRoute( builder: (context, state, child) { return WillPopScope( onWillPop: () async { // 拦截Web端浏览器返回操作 return false; }, child: Scaffold( body: child, // 你的导航栏布局 ), ); }, // ... 子路由 ),
3. 优化路由状态传递
移除全局变量startPage,改为通过路由参数传递:
// HomePage接收参数 class HomePage extends StatelessWidget { final int startPage; const HomePage({Key? key, this.startPage = 0}) : super(key: key); // ... 页面逻辑 } // 路由中传递参数 GoRoute( name: 'portfolio', path: 'portfolio', builder: (context, state) => const HomePage(startPage: 1), ),
三、额外注意事项
- 确保
detectPage()返回的主题和路由配置不会与GoRouter的内部配置冲突,建议将主题逻辑整合到Provider中管理 - 测试时清除浏览器缓存,避免状态残留导致闪屏页不显示
内容的提问来源于stack exchange,提问作者Feinliebe
相关产品推荐
相关产品推荐

