I use flushbar to display in-app notifications to the user, but I think this issue applies to any widget that one wants to overlay over the current screen, such as a snackbar.
I want to be able to display a notification that is independent of the navigation between screens, i.e., if the user navigates between the screens the notification should stay across all screens. Because the flushbar notification is drawn over the current BuildContext only, as soon as the user closes the current screen, the notification disappears as well (because the notification widget is part of that screen's widget subtree).
Is there a way to display a widget (such as a notification) on top of the entire app, no matter the navigation?
EDIT1: Added example code.
import 'package:flushbar/flushbar_route.dart' as route;
import 'package:flushbar/flushbar.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FirstScreen(),
);
}
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: RaisedButton(
child: Text('go to second screen'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (BuildContext context) => SecondScreen())
);
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
final Flushbar _flushbar = Flushbar(message: 'Flushbar Notification');
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Screen'),
),
body: Center(
child: RaisedButton(
child: Text('show flushbar'),
onPressed: () {
showFlushbar(_flushbar, context);
},
),
),
);
}
}
Future showFlushbar(Flushbar instance, BuildContext context) {
final _route = route.showFlushbar(
context: context,
flushbar: instance,
);
return Navigator.of(context, rootNavigator: true).push(_route);
}
The result will look like this (when going back to the first screen I would want the notification to stay on the screen):
EDIT2: George's solution works. Additionally, using overlays might be a suitable solution for others as well (see this blog post), i.e., the overlay stays on-screen even during route navigation. However, the overlay solution is less elegant in my case because it doesn't allow the flushbar to be dismissible or animated (or at least it's not as straightforward).
Related question: Flutter - Application Wide Notifications
Try displaying your Flushbar from the root Navigator.
Looking at the sources of flushbar lib, we can create our own Flushbar route by importing showFlushbar
method from package:flushbar/flushbar_route.dart
.
e.g.
import 'package:flushbar/flushbar_route.dart' as route;
// ...
Future showFlushbar(Flushbar instance) {
final _route = route.showFlushbar(
context: context,
flushbar: instance,
);
return Navigator.of(context, rootNavigator: true).push(_route);
}
Thank you for the added code in your question.
The ultimate solution, in my opinion, is creating another Navigator
right inside of MaterialApp
- some kind of a second 'sub-root' navigator.
Now you will be able to choose between 2 layers of Navigator
depending on your needs.
Navigator.of(context, rootNavigator: true)
will return the top-level Navigator - use it for your Flushbar or any other modal popups that you want to keep persistent above all screens.
Navigator.of(context)
, where rootNavigator
is false
by default. Use it to get the 'sub-root' Navigator to display new screens / pages.
e.g. placing another Navigator
right in the MaterialApp
.
MaterialApp(
home: Navigator( // 'sub-root' navigator. Second in the hierarchy.
onGenerateRoute: (_) => MaterialPageRoute(
builder: (_) => FirstScreen(),
settings: RouteSettings(isInitialRoute: true),
),
),
);
Let me know if this helped.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With