Reputation: 636
I'm trying to display a SnackBar
after performing an action from the AppBar
.
The AppBar
cannot be built from a builder so it can't access is Scaffold ancestor.
I know we can use a GlobalKey
object to access the context whenever we want, but I would like to know if there is a solution without using the GlobalKey
.
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/9380
Some more context:
I have an Appbar
with a PopupMenuButton
, which have one item. When the user click on this item I display a dialog which the showDialog
method and if the user clicks on "ok" I want to display a SnackBar
Upvotes: 10
Views: 4861
Reputation: 224
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);
},
);
},
),
],
)
);
Upvotes: 14
Reputation: 20558
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),
),
),
];
},
)
],
),
);
}
}
Upvotes: 1
Reputation: 815
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(...),
),
),
Upvotes: 9