Flutter启动页报错:Navigator操作使用无Navigator的Context如何解决?
报错信息
FlutterError (Navigator operation requested with a context that does not include a Navigator. The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.)
问题原因
你在SplashScreen的initState里使用的上下文属于SplashScreen组件本身,而包含Navigator的MaterialApp是在SplashScreen的build方法中创建的——这个上下文并非Navigator的后代,因此调用Navigator.pushReplacement会触发错误。即便添加了Builder,initState执行时MaterialApp还未完成渲染,Builder的上下文也无法被正确调用。
解决方案(无需onPress)
方案一:调整组件结构(推荐)
将MaterialApp作为根组件,让SplashScreen作为它的home,这样SplashScreen的上下文自然成为Navigator的后代。
修改main.dart:
Future<void> main() async { await SentryFlutter.init( (options) { options.dsn = _sentryDSN; options.tracesSampleRate = _sentryTracesSampleRate; options.attachStacktrace = true; options.enableAppLifecycleBreadcrumbs = true; }, appRunner: () => runApp(const MyApp()), ); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( home: const SplashScreen(), ); } }
修改SplashScreen代码:
import 'package:flutter/material.dart'; import 'package:loopcycle/screens/loopcycle_main.dart'; class SplashScreen extends StatefulWidget { const SplashScreen({Key? key}) : super(key: key); @override State<SplashScreen> createState() => _SplashScreenState(); } class _SplashScreenState extends State<SplashScreen> { @override void initState() { super.initState(); _navigateToMainApp(); } void _navigateToMainApp() async { await Future.delayed(const Duration(milliseconds: 2000), () { Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => const LoopcycleMainApp())); }); } @override Widget build(BuildContext context) { return const Center( child: Text("test"), ); } }
方案二:等待渲染完成后获取正确上下文
如果不想调整组件结构,可以通过WidgetsBinding等待第一帧渲染完成,再使用Builder保存的上下文进行跳转。
修改SplashScreen代码:
import 'package:flutter/material.dart'; import 'package:loopcycle/screens/loopcycle_main.dart'; class SplashScreen extends StatefulWidget { const SplashScreen({Key? key}) : super(key: key); @override State<SplashScreen> createState() => _SplashScreenState(); } class _SplashScreenState extends State<SplashScreen> { BuildContext? _navigatorContext; @override void initState() { super.initState(); // 等待页面第一帧渲染完成,确保Builder的上下文已初始化 WidgetsBinding.instance.addPostFrameCallback((_) { _navigateToMainApp(); }); } void _navigateToMainApp() async { await Future.delayed(const Duration(milliseconds: 2000), () { if (_navigatorContext != null) { Navigator.pushReplacement(_navigatorContext!, MaterialPageRoute(builder: (context) => const LoopcycleMainApp())); } }); } @override Widget build(BuildContext context) { return MaterialApp( home: Builder( builder: (context) { _navigatorContext = context; // 保存Navigator后代的上下文 return const Center( child: Text("test"), ); }), ); } }
注意事项
方案一的组件结构更符合Flutter设计规范,后续扩展页面路由也更便捷,优先推荐使用。
内容的提问来源于stack exchange,提问作者Zinox

