Flutter Navigator报错:无Navigator的BuildContext问题排查
点击页面中的悬浮按钮(FloatingActionButton)时出现上述错误,但列表内的编辑、删除、添加按钮均可正常工作,原添加笔记功能也能正常运行。推测问题出在BuildContext上,可能和Future/async/await有关。
以下是main.dart的代码:
import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'add.dart'; import 'firebase_options.dart'; import 'note.dart'; import 'package:intl/intl.dart'; import 'edit.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); runApp(MainApp()); } class MainApp extends StatefulWidget { @override _MainAppState createState() => _MainAppState(); } class _MainAppState extends State<MainApp> { List<Note> listNotes = [ Note(title: '1', content: 'abracadabra', lastEdited: DateTime.parse('2024-08-05')), Note(title: '2', content: 'abracadabra', lastEdited: DateTime.parse('2024-08-06')), Note(title: '3', content: 'abracadabra', lastEdited: DateTime.parse('2024-08-07')), ]; final FirebaseManager firebaseManager = FirebaseManager(); late Future<List<Note>> _notesFuture; void _fetchNotes() { setState(() { _notesFuture = firebaseManager.getNotes(); }); } @override void initState() { super.initState(); firebaseManager.addNotes(listNotes); _fetchNotes(); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text('Notes'), ), body: FutureBuilder<List<Note>>( future: _notesFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return Center(child: Text('No notes available')); } else { List<Note> notes = snapshot.data!; return ListView.builder( itemCount: notes.length, itemBuilder: (context, index) { Note note = notes[index]; return ListTile( title: Text(note.title), subtitle: Text(note.content), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.edit), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => EditNoteScreen(note: note,firebaseManager: firebaseManager,), ), ).then((value) => { if (value == true){ _fetchNotes() } }); }, ), IconButton( icon: Icon(Icons.delete), onPressed: () async { await firebaseManager.deleteNoteByFieldId(note.id); _fetchNotes(); }, ), IconButton( icon: Icon(Icons.add), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => AddNoteScreen(firebaseManager: firebaseManager), ), ).then((value) => { if (value == true){ _fetchNotes() } }); }, ) ], ), ); }, ); } }, ), floatingActionButton: FloatingActionButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => AddNoteScreen(firebaseManager: firebaseManager), ), ).then((value) => { if (value == true){ _fetchNotes() } }); }, child: Icon(Icons.add), ), ), ); } }
问题原因
报错的核心原因是:你在_MainAppState的build方法中直接返回MaterialApp,而悬浮按钮使用的context是MainApp组件的上下文——这个上下文位于MaterialApp的外部,并不包含Navigator实例(Navigator是由MaterialApp提供的)。而列表中的按钮使用的是FutureBuilder或ListView.builder内部的上下文,这些上下文属于MaterialApp的子树,因此能正常访问到Navigator。
修复方法
方法1:将主页面内容抽成独立Widget
把包含Scaffold的部分提取为一个单独的Widget,这样它的上下文就属于MaterialApp的子树,能正常访问Navigator:
// 新增独立Widget class NotesHomePage extends StatefulWidget { final FirebaseManager firebaseManager; final Future<List<Note>> notesFuture; final Function() fetchNotes; const NotesHomePage({ Key? key, required this.firebaseManager, required this.notesFuture, required this.fetchNotes, }) : super(key: key); @override _NotesHomePageState createState() => _NotesHomePageState(); } class _NotesHomePageState extends State<NotesHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Notes'), ), body: FutureBuilder<List<Note>>( future: widget.notesFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center(child: Text('No notes available')); } else { List<Note> notes = snapshot.data!; return ListView.builder( itemCount: notes.length, itemBuilder: (context, index) { Note note = notes[index]; return ListTile( title: Text(note.title), subtitle: Text(note.content), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.edit), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => EditNoteScreen(note: note,firebaseManager: widget.firebaseManager,), ), ).then((value) { if (value == true){ widget.fetchNotes(); } }); }, ), IconButton( icon: const Icon(Icons.delete), onPressed: () async { await widget.firebaseManager.deleteNoteByFieldId(note.id); widget.fetchNotes(); }, ), IconButton( icon: const Icon(Icons.add), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => AddNoteScreen(firebaseManager: widget.firebaseManager), ), ).then((value) { if (value == true){ widget.fetchNotes(); } }); }, ) ], ), ); }, ); } }, ), floatingActionButton: FloatingActionButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => AddNoteScreen(firebaseManager: widget.firebaseManager), ), ).then((value) { if (value == true){ widget.fetchNotes(); } }); }, child: const Icon(Icons.add), ), ); } } // 修改MainApp的build方法 @override Widget build(BuildContext context) { return MaterialApp( home: NotesHomePage( firebaseManager: firebaseManager, notesFuture: _notesFuture, fetchNotes: _fetchNotes, ), ); }
方法2:使用GlobalKey获取Navigator状态
在MainApp中定义一个全局的NavigatorState key,通过它来直接调用Navigator方法:
class _MainAppState extends State<MainApp> { // 新增GlobalKey final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>(); // 其他代码保持不变... @override Widget build(BuildContext context) { return MaterialApp( navigatorKey: _navigatorKey, // 绑定key home: Scaffold( // 其他代码不变... floatingActionButton: FloatingActionButton( onPressed: () { // 使用_globalKey获取Navigator _navigatorKey.currentState?.push( MaterialPageRoute( builder: (context) => AddNoteScreen(firebaseManager: firebaseManager), ), ).then((value) { if (value == true){ _fetchNotes(); } }); }, child: const Icon(Icons.add), ), ), ); } }
内容的提问来源于stack exchange,提问作者CriticalError
相关产品推荐
相关产品推荐

