Flutter: How to display a snackbar from an appbar action
Solution 1
You can use the Builder widget
Example:
Scaffold(
appBar: AppBar(
actions: <Widget>[
Builder(
builder: (BuildContext context) {
return IconButton(
icon: const Icon(Icons.message),
onPressed: () {
final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
Scaffold.of(context).showSnackBar(snackBar);
},
);
},
),
],
)
);
Solution 2
The Scaffold.appBar
parameter requires a PreferredSizeWidget
, so you can have a Builder
there like this:
appBar: PreferredSize(
preferredSize: Size.fromHeight(56),
child: Builder(
builder: (context) => AppBar(...),
),
),
Solution 3
An option is to use two contexts in the dialog and use the context passed to the dialog to search for the Scaffold
.
When you show a dialog, you are displaying a completely different page/route which is outside the scope of the calling page. So no scaffold is available.
Below you have a working example where you use the scope of the first page.
The problem, though, is that the SnackBar
is not removed.
If instead you use a GlobalKey
to get the Scaffold
the problem is the same.
I would consider not using a Snackbar in this case, because it is associated to the page below. It is even greyed out by the dialog shadow.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
_showDialog(BuildContext context1) {
return showDialog(
context: context1,
builder: (BuildContext context) {
return AlertDialog(
content: Text("Dialog"),
actions: <Widget>[
new FlatButton(
child: new Text("OK"),
onPressed: () => Scaffold.of(context1).showSnackBar(SnackBar(
content: Text("Pressed"),
)),
),
],
);
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Test"),
actions: <Widget>[
PopupMenuButton(
itemBuilder: (BuildContext context) {
return <PopupMenuEntry>[
PopupMenuItem(
child: ListTile(
title: Text('Show dialog'),
onTap: () => _showDialog(context),
),
),
];
},
)
],
),
);
}
}
Quentin
Updated on December 08, 2022Comments
-
Quentin over 1 year
I'm trying to display a
SnackBar
after performing an action from theAppBar
. TheAppBar
cannot be built from a builder so it can't access is Scaffold ancestor. I know we can use aGlobalKey
object to access the context whenever we want, but I would like to know if there is a solution without using theGlobalKey
. I found some github issues and pull-request, but I can't find a solution from them => https://github.com/flutter/flutter/issues/4581 and https://github.com/flutter/flutter/pull/9380Some more context: I have an
Appbar
with aPopupMenuButton
, which have one item. When the user click on this item I display a dialog which theshowDialog
method and if the user clicks on "ok" I want to display aSnackBar
-
Quentin over 5 yearsI tried your solution, but when I pass the context to the method which build my alert, and then when I try to display the SnackBar, with this context, I still have the
Scaffold.of() called with a context that does not contain a Scaffold
error. -
Quentin over 5 yearsI added more context to my question. I didn't test your solution but I want to display the
SnackBar
after a dialog from aPopupMenuButton
item -
chemamolins over 5 yearsI have changed my answer according to the additional information you have provided.
-
Quentin over 5 yearsI tested it. I can't find the way to integrate it with my code due to some weird behaviors but it's working. But there are a few problems: the SnackBar does not disappear and the action menu does not disappear by itself.
-
AlanKley about 5 yearsThis solution worked for me. My call: actions: <Widget>[ new IconButton(icon: const Icon(Icons.settings), onPressed: () =>_handleSettings(Scaffold.of(context))), ],
-
WSBT about 5 yearsThis works as is,
builder: (context) => AppBar(...),
: make sure you write your AppBar code inside the brackets right there. It stops working if you extract the AppBar into a variable or method. -
vishalknishad over 3 yearsthis is what i was looking for