I understand the problem but I don't know the solution.
In main.dart I have a Scaffold with a Drawer menu. The Drawer menu provides a link to the About page.
builder: (BuildContext context, themeProvider, child) {
return MaterialApp(
home: Scaffold(
endDrawer: MenuDrawer(),
body: MaterialApp.router(
routerConfig: _appRouter.config(),
),
), //end Scaffold
); //end MaterialApp
This loads my initial route (the HOME page).
Inside the Menu Drawer the "About" button link is coded like this:
OutlinedButton(
child: const Text("ABOUT PAGE"),
onPressed: () {
context.router.pushNamed('/about');
},
),
....but when I press this button I get the error:
══╡ EXCEPTION CAUGHT BY GESTURE
The following assertion was thrown while handling a gesture: AutoRouter operation requested with a context that does not include an AutoRouter. The context used to retrieve the Router must be that of a widget that is a descendant of an AutoRouter widget.
As I understand it, this is because the menu drawer resides in the main body, not in the body of "home". But I don't want to have a menu for each specific page (or an appbar and menu for each page)...I just want one above all the pages. So how do I modify my onPressed code to work?
If I understood correctly, you may just simplify your setup a little to avoid additional nesting (MaterialApp.router
inside MaterialApp
). That's how you'll have a single context for all pages:
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: _appRouter.config(),
builder: (context, router) {
return Scaffold(
endDrawer: MenuDrawer(),
body: router,
);
},
);
}
Another option is to use nested navigation. After discussion in comments, I actually think it's more robust way.
First, read about nested navigation [here]
Config has to be modified:
@AutoRouterConfig()
class AppRouter extends RootStackRouter {
@override
List<AutoRoute> get routes => [
// nesting starts here.
AutoRoute(
path: '/',
page: RootRoute.page,
children: [
// sample routes
AutoRoute(path: '', page: HomeRoute.page),
AutoRoute(path: 'about', page: AboutRoute.page),
],
),
];
}
So now you have 3 pages: RootPage
, HomePage
, AboutPage
. HomePage
and AboutPage
are actual pages with your content (so they have different names I guess). RootPage
is technical page and should include all your drawers, appears and other navigation-specific stuff. Example:
@RoutePage()
class RootPage extends StatelessWidget {
const RootPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return AutoTabsScaffold(
appBarBuilder: (_, tabsRouter) => AppBar(
title: const Text('My App'),
),
endDrawer: const MenuDrawer(),
);
}
}
You main build
method will look like this now:
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: _appRouter.config(),
);
}
Meaning you provides only router config to build method and AutoRouter
takes care of other things.
I also created a GitHub example to better explain the concept, repository is here. Feel free to look and use in your code, it needed.