Flutter使用MaterialApp.router+GoRouter时全局Overlay加载无法显示
解决GoRouter下全局Overlay加载不显示的问题
问题根源在于你把ref.listen放在了MaterialApp.router的外部,这里的context不属于MaterialApp的上下文树,无法找到Overlay的挂载入口。而旧代码里的监听是在MaterialApp的home参数内部的Consumer中,用的是MaterialApp内部的上下文,能正确访问Overlay。
下面给两种可行的修改方案:
方案一:用MaterialApp.router的builder参数注入监听
把监听逻辑移到MaterialApp.router的builder参数里,这里的context是MaterialApp内部的上下文,能正确获取Overlay:
final router = ref.watch(routerProvider); return MaterialApp.router( title: 'my app', theme: ThemeData( brightness: Brightness.dark, primarySwatch: Colors.blue, indicatorColor: Colors.blueGrey, ), darkTheme: ThemeData.dark(), themeMode: ThemeMode.dark, debugShowCheckedModeBanner: false, routeInformationParser: router.routeInformationParser, routerDelegate: router.routerDelegate, builder: (context, child) { return Consumer( builder: (context, ref, child) { ref.listen<bool>(isLoadingProvider, (_, isLoading) { if (isLoading) { LoadingScreen.instance().show(context: context); } else { LoadingScreen.instance().hide(); } }); return child!; }, ); }, );
方案二:在GoRouter的ShellRoute中添加监听
如果你的路由结构用了ShellRoute,可以把监听逻辑放在Shell的builder里,这样所有子路由都会共享这个监听,且上下文正确:
final routerProvider = Provider<GoRouter>((ref) { return GoRouter( routes: [ ShellRoute( builder: (context, state, child) { return Consumer( builder: (context, ref, child) { ref.listen<bool>(isLoadingProvider, (_, isLoading) { if (isLoading) { LoadingScreen.instance().show(context: context); } else { LoadingScreen.instance().hide(); } }); return child!; }, ); }, routes: [ GoRoute(path: '/', builder: (context, state) => const MainView()), GoRoute(path: '/auth', builder: (context, state) => const AuthPage()), // 其他路由... ], ), ], ); });
关键说明
不管哪种方案,核心都是确保调用LoadingScreen.show时用的是MaterialApp.router内部的上下文——只有这样,Overlay.of(context)才能找到正确的Overlay实例,加载弹窗才能正常挂载到全局层级。
内容的提问来源于stack exchange,提问作者omar hadek
相关产品推荐
相关产品推荐

