Reputation: 883
I'm developing a web/desktop application that has a fairly standard UI layout involving a NavigationRail
on the left and a content pane taking up the remainder of the screen.
I've reciently added go_router
so I can properly support URLs in web browsers, however in doing so I have lost the ability to have any form of transition/animation when moving between pages as calling context.go()
causes a hard cut to the next page.
Theres also the issue that go_router
routes have to return the full page to be rendered meaning I need to include the navigation rail on every page rather than each page being just the content relevant to that page. I believe this is also the main reason all animations are broken, because clicking a link effectively destroys the current navigation rail and builds a new one for the new page
I couldn't see anything in go_router
but is there any form of builder API available that can output and refresh a single section of the page? I'm thinking of something like bloc
's BlocBuilder
which listens for state changes and rebuilds just the widget its responsible for when a change occures.
Alternatively, is there a way to update the current URL without rebuilding the whole page?
Or is go_router
just not capable of what I'm after, and if so, are there any alternatives that can do this?
The overall effecti I'm after is similar to the material site https://m3.material.io/develop Clicking around the various buttons feels like you are navigating around within an app rather than clicking on links and loading new pages
Thanks for your help
Upvotes: 8
Views: 2913
Reputation: 12503
I solved this with a Shell Route. I got the idea when going through the go_router 5 migration guide. I saw that they had a navigatorBuilder
property in which they were wrapping every route in a Scaffold with AppBar. And it said to migrate:
Before migration:
final GoRouter router = GoRouter(
routes: <GoRoute> [
GoRoute(
path: '/',
builder: (_, __) => const Text('/'),
),
GoRoute(
path: '/a',
builder: (_, __) => const Text('/a'),
)
],
navigatorBuilder: (BuildContext context, GoRouterState state, Widget child) {
return Scaffold(
appBar: AppBar(title: Text(state.location)),
body: child,
);
}
);
After Migration:
final GoRouter router = GoRouter(
routes: <GoRoute> [
ShellRoute(
builder: (_, GoRouterState state, child) {
return Scaffold(
body: child,
appBar: AppBar(title: Text(state.location)),
);
},
routes: [
GoRoute(
path: 'a',
builder: (_, __) => const Text('a'),
),
GoRoute(
path: 'b',
builder: (_, __) => const Text('b'),
)
],
),
],
);
Now every route in the ShellRoute.routes
property will be wrapped with that Scaffold
and AppBar
, it will not rebuild upon navigation, so will behave as a persistent AppBar
, NavigationBar
, or whatever should. Now it shows the page transition animations when you do context.go('some_route')
(for example from a NavigationBar
in the ShellRoute
). You also don't run into the issue Felix ZY was having, accessing GoRouter
from the context
.
A NavigationRail
would just be like this in the shell route:
ShellRoute(
builder: (_, GoRouterState state, child) {
return Scaffold(
body: Column(children:[Row(
children: <Widget>[
NavigationRail(....)]),
child,]));
});
}
Upvotes: 2