问题
Is there a correct way to listen to a stream / scoped model from a 'root' page or location in a Flutter app and upon receiving some data display an appropriate notification (e.g. Snackbar) on any currently open page (may not be the home page)?
I'd like to be able to display certain notifications across the entire application and not just on a page by page basis.
Here I have a home page that's my apps initial page, it starts listening to a stream from a scoped_model retrieved from context and whenever data is received displays a dialog regardless of the page the user is visiting.
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
MyService service = ScopedModel.of<MyService>(context);
service.events.stream.listen((data) {
showDialog<String>(
context: context,
barrierDismissible: true, // dialog is dismissible with a tap on the barrier
builder: (BuildContext context) {
return AlertDialog(
title: Text('An Event has Occurred'),
content: Text('$data'));});
});
return Scaffold(
//Navigator Push Routes - Page 1 / Page 2 / Page 3 / etc
);}
This kind of works but really doesn't feel correct - has anyone done this before who could offer a better solution?
I could add a similar listener to every page but again that seems really unnecessary
回答1:
I've done something mildly similar. Though you really should place this in a statefulwidget, add the listener in the initstate and not in the widget build method of a stateless widget.
回答2:
++++ Update July 2019 ++++
I wrote a Package that supports application wide message display.
EZ Flutter is a collection of widgets, packages and many more usefull things, mixed up in little framework. The aim is to make standard features available from scratch. EZ Flutter supports displaying a message to the user from anywhere inside the app with just one line of code.
Github : https://github.com/Ephenodrom/EZ-Flutter
dependencies:
ez_flutter: ^0.2.0
Check out the documentation how using different configurations works.
https://github.com/Ephenodrom/EZ-Flutter/blob/master/documentation/GLOBAL_MESSAGE.md
++++ Old Answer ++++
Maybe this example will help :
https://github.com/Ephenodrom/Flutter-Advanced-Examples/tree/master/lib/examples/globalMessage
The idea is to have a messagewrapper widget that displays messages with a snackbar that are pushed into a BLOC.
class GlobalMessageWrapper extends StatefulWidget {
final Widget child;
GlobalMessageWrapper(this.child);
@override
_GlobalMessageWrapperState createState() => _GlobalMessageWrapperState();
}
class _GlobalMessageWrapperState extends State<GlobalMessageWrapper> {
@override
Widget build(BuildContext context) {
return StreamBuilder(
initialData: null,
stream: BlocProvider.of<GlobalBloc>(context).messageBloc.messageStream,
builder: (BuildContext context, AsyncSnapshot<Message> snapshot) {
Message msg = snapshot.data;
if (msg != null) {
WidgetsBinding.instance
.addPostFrameCallback((_) => _showMessage(msg));
}
return Container(child: widget.child);
});
}
void _showMessage(Message message) {
Color color = Colors.grey;
switch (message.type) {
case "success":
color = Colors.green;
break;
case "info":
color = Colors.blue;
break;
case "warning":
color = Colors.orange;
break;
case "error":
color = Colors.red;
break;
default:
}
SnackBar bar = SnackBar(
content: Padding(
padding: const EdgeInsets.only(bottom: 50.0),
child: Text(message.text),
),
backgroundColor: color);
Scaffold.of(context)
..hideCurrentSnackBar()
..showSnackBar(bar);
}
}
To use the Wrapper globally in your app, put him on top of the widget tree. You could put it under your MaterialApp Widget in the main.dart file.
来源:https://stackoverflow.com/questions/56480195/flutter-application-wide-notifications