I am trying to get a navigator to work on my icons. I have all my icons laid out in a column, which persists across all my screens and I want to be able to go to different screens when I click an icon on the left within my menu. The icons in the bottom right corner have been disabled, I am just using those to refer to the first and second page.
I have set up a navigator within the MyApp widget, which has routes to a couple test pages called firstpage and secondpage, although when I click the icons and try to route over to the another page I get this error:
The following assertion was thrown while handling a gesture:
Navigator operation requested with a context that does not include a Navigator.
I’m assuming that I am not using the navigator correctly but I’m not sure what I need to do.
main.dart
import 'package:flutter/material.dart';
import 'package:practice3/secondpage.dart';
import 'firstpage.dart';
import 'package:flutter/services.dart';
import 'persistentmenu.dart';
import 'persistentrow.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations(
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight],
).then((_) {
runApp(const MyApp());
});
}
class BaseWidget extends StatelessWidget {
final Widget child;
const BaseWidget({required this.child});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Container(child: child),
PersistentRow(),
PersistentMenu(),
],
)
);
}
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
builder: (context, child) => BaseWidget(child: child!),
initialRoute: '/',
routes: {
'/': (context) => FirstPage(),
'/second': (context) => SecondPage(),
},
);
}
}
persistentmenu.dart
import 'package:flutter/material.dart';
import 'firstpage.dart';
import 'secondpage.dart';
class PersistentMenu extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SafeArea(
child: Align(
alignment: Alignment.bottomLeft,
child: Container(
width: 80,
height: 800,
//margin: EdgeInsets.only(right: 25),
color: Color.fromRGBO(2, 58, 107, 1),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
padding: EdgeInsets.all(0.0),
icon: Image.asset('assets/icons/Back.png'),
onPressed: () {
Navigator.pushNamed(context, '/'); // Route to firstpage.dart
},
),
IconButton(
padding: EdgeInsets.all(0.0),
icon: Image.asset('assets/icons/tip_load.png'),
onPressed: () {},
),
IconButton(
padding: EdgeInsets.all(0.0),
icon: Image.asset('assets/icons/tip_eject.png'),
onPressed: () {},
),
IconButton(
padding: EdgeInsets.all(0.0),
icon: Image.asset('assets/icons/Light.png'),
onPressed: () {},
),
IconButton(
padding: EdgeInsets.all(0.0),
icon: Image.asset('assets/icons/Utility.png'),
onPressed: () {
Navigator.pushNamed(context, '/second'); // Route to secondpage.dart
},
),
IconButton(
padding: EdgeInsets.all(0.0),
icon: Image.asset('assets/icons/Help.png'),
onPressed: () {},
),
IconButton(
padding: EdgeInsets.all(0.0),
icon: Image.asset('assets/icons/User.png'),
onPressed: () {},
),
IconButton(
padding: EdgeInsets.all(0.0),
icon: Image.asset('assets/icons/Power.png'),
onPressed: () {},
),
],
),
),
),
);
}
}
secondpage.dart
import 'package:flutter/material.dart';
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Align(
alignment: Alignment.bottomRight,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
ElevatedButton.icon(
onPressed: () {
//Navigator.pushNamed(context, '/');
},
icon: Icon(Icons.arrow_back_outlined),
label: Text('Back to first Page'),
),
],
),
),
);
}
}
3
Answers
In second Navigator. pushNamed you need to use ‘/second’ because that is the route that you have named in your main. dart file
The
builder
property is built below the Navigator, soNavigator.of(context)
will not be able to find anything. In order to use the Navigator, you need another way to access the state.If you don’t need BaseWidget below the Navigator, you can simply add it as the base for both pages instead.
If you need BaseWidget below the Navigator (so the persistent elements will stay still during transitions), you will need to create a
GlobalKey<NavigatorState>
and pass it to both the MaterialApp and BaseWidget. You can then access the NavigatorState viakey.currentState!
.I’ve replicated this error and have fixed it. Read below for detailed solution.
Explanation: –
Actually, when you were passing the ‘context’ in persistentmenu.dart
You were using the context of ‘persistentmenu.dart’ file which was linked to the ‘context’ of ‘BaseWidget’ buildContext and in short that context was passed by the ‘MyApp’ class(right below the BaseWidget class) as argument due to which Navigator was unable to find the context of MaterialApp and error was being popped.
Now there can be multiple ways to solve it as you need to somehow pass MaterialApp Context to it so that when you use the PushNamed which is actually translated to
So you could pass the MaterialApp context or atleast the context from where the dart analyzer can go upward and search for the context of MaterialApp(Because navigator is defined in MaterialApp).
There can be multiple ways to solve this but I solved it as follow.
Solution
Simply create a new class to store GlobalKey Context of MaterialApp
NavigatorService.dart
Refactor ‘MyApp’ class as follow, just pass the MaterialApp context to the GlobalKey.
main.dart
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
and replace the above context with ‘context’ used in Navigator.pushNamed
firstpage.dart
Do the same for second page as well. // Route to secondpage.dart
I hope this will solve the issue.