We need close one screen and open a second screen. And show snackbar on the second screen from first screen.
I tried to use Navigator.push
, but this screen is already open and we have this error
Bad state: Stream has already been listened to.
We need close one screen and open a second screen. And show snackbar on the second screen from first screen.
I tried to use Navigator.push
, but this screen is already open and we have this error
Bad state: Stream has already been listened to.
Instead of Snackbar i would suggest you to use Flushbar plugin for flutter it is easy to use and it'll take care of everything and u can customize it to a great extent . Snackbar needs a scaffold ancestor to work but Flushbar doesn't and it takes care of all the extra stuff itself and provides with ton of cool features.
I'm not sure I understand 100% the use case you have but by returning results from screens and passing arguments to new routes, you can work around basically any scenario.
Let's take an example. A is the original screen, then you push screen B. Now you see B, perform some action there, pop it, you get back to screen A and you want to display a snackbar.
When you pop
, you can return a result and handle that result from the "parent" screen as described in the "Return data from a screen" cookbook.
When you receive a result, you can either show a snackbar notification, or alternatively (in case there is a third screen), you can pass that result to another screen as argument.
Please read this documentation by Flutter that answers your question with example.
What you have to do is, when you are going to Navigator.pop
you can pass a message and based on that message you can show SnackBar
in the previous screen where you did Navigator.push
So when you pop do something like this:
Navigator.pop(context, 'Yes');
Navigator.pop(context, 'No');
Here, you are passing a message and based on this message you can show the Snackbar in the previous screen where you pushed like this:
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SelectionScreen()),
);
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result.
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text('$result')));
showSubmitRequestSnackBar(BuildContext context) async {
Flushbar(
flushbarPosition: FlushbarPosition.BOTTOM,
message: "Request Successfully Saved",
icon: Icon(
Icons.info_outline,
size: 28.0,
color: Colors.red,
),
backgroundColor: Colors.red,
duration: Duration(seconds: 5),
leftBarIndicatorColor: Colors.red,
)
..show(context).then((r)=> Navigator.push(
context, MaterialPageRoute(builder: (context) => ListPage(""))));
}
Screen A
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BScreen(
callbackFunction: (String resMessage){
print(resMessage);
},
),
),
);
Screen B
class BScreen extends StatefulWidget {
final Function callbackFunction;
BScreen({required this.callbackFunction});
@override
_BScreenState createState() => _BScreenState();
}
class _BScreenState extends State<BScreen> {
//
_performTask(){
// add your task here
// ..........
String msg = 'Task has been added';
widget.callbackFunction(msg);
Navigator.of(context).pop();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
_performTask();
},
child: Text('Click Here'),
),
),
);
}
}
This solution worked for me. Happy to help others :) Thanks for asking this question.