Reputation: 14656
In Flutter, is there any way to listen for navigation changes?
Example: Navigation is triggered in Widget A
:
Navigator.of(context).pushNamed('/chat');
When the above code is executed, I want an event to fire in a child of Widget A
. Is this possible?
Upvotes: 11
Views: 13088
Reputation: 320
If you using GoRouter, you can create class extends NavigatorObserver, then put it into observer of GoRouter's constructor, and put it into StatefulShellBranch if you have.
Example:
final router = GoRouter(
initialLocation: '/',
navigatorKey: rootNavigatorKey,
observers: [GoRouterObserver()], // <== add here
routes: <RouteBase>[
GoRoute(
path: pathOnboarding,
pageBuilder: (context, state) {
return const NoTransitionPage(
child: Scaffold(
body: SafeArea(
child: Center(
child: Text('Onboard Page'),
),
),
),
);
},
),
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
return MainPage(
navigationShell: navigationShell,
currentPath: state.fullPath,
);
},
branches: [
StatefulShellBranch(
navigatorKey: homeShellNavigatorKey,
observers: [GoRouterObserver()], // <=== add here
routes: [
GoRoute(
path: pathHome,
pageBuilder: (context, state) =>
const NoTransitionPage(
child: HomePage(),
),
),
],
),
],
),
],
debugLogDiagnostics: true,
);
class GoRouterObserver extends NavigatorObserver {
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
debugPrint('GoRouterObserver didPush: $route');
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
debugPrint('GoRouterObserver didPop: $route');
}
@override
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
debugPrint('GoRouterObserver didRemove: $route');
}
@override
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
debugPrint('GoRouterObserver didReplace: $newRoute');
}
}
Upvotes: 1
Reputation: 113
I came across a similar problem and in my case, the best solution was using MaterialApp
's onNavigationNotification
, like this:
MaterialApp(
onNavigationNotification: (notification) {
print('something changed');
// your logic to notify your widget
return notification.canHandlePop;
},
);
This way, you'll get notified when a navigation event occurs and you can add your own logic for notifying Widget A
that a navigation event happened. To notify Widget A
, or any widgets inside your app, you could use a ChangeNotifier
or flutter_bloc's Bloc
, for example.
This solution worked great for me because I just needed to notify a widget when something happened in the navigation stack, and I used ModalRoute
's isCurrent
to check if the widget was still part of the current route after the navigation event occurred.
Upvotes: 2
Reputation: 983
Use RouteObserver :
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
then add this to root materialApp widget :
MaterialApp(
theme: ThemeData(),
navigatorObservers: [routeObserver],
)
we need to implement RouteAware in every widget that might be push or pop into the routes stack.
class Screen extends State<Screen3> with RouteAware{
...
@override
void didChangeDependencies() {
super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute<dynamic>);
}
@override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}
@override
void didPush() {
final route = ModalRoute.of(context)?.settings.name;
print('didPush route: $route');
}
@override
void didPopNext() {
final route = ModalRoute.of(context)?.settings.name;
print('didPopNext route: $route');
}
@override
void didPushNext() {
final route = ModalRoute.of(context)?.settings.name;
print('didPushNext route: $route');
}
@override
void didPop() {
final route = ModalRoute.of(context)?.settings.name;
print('didPop route: $route');
}
...
}
Upvotes: 16