Display SnackBar in Flutter
Solution 1
There's three problems. The first is that you don't have a Scaffold anywhere, and the Scaffold widget is the one that knows how to show snack bars. The second is that you have a key for getting a hold of the scaffold, but you've put it on a Padding instead (and Paddings don't have any knowledge of snack bars). The third is that you've used the key before the widget that it's associated with has had a chance to be initialised, since initState is called before build.
The simplest solution is to change the home
line in your MyApp widget to:
home: new Scaffold(body: new MyHomePage()),
...and then remove all mention of _scaffoldKey
and instead use Scaffold.of(context)
where you currently have _scaffoldKey.currentState
.
Solution 2
In my case i had code like this (in class state)
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
void showInSnackBar(String value) {
_scaffoldKey.currentState.showSnackBar(new SnackBar(content: new Text(value)));
}
but i didn't setup the key for scaffold. so when i add key: _scaffoldKey
@override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
body: new SafeArea(
snackbar start to work :)
Solution 3
There's a better and cleaner way to display a Snackbar in flutter. I found it the hard way and sharing so that maybe it's helpful for someone else.
No need to change in your main app part
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'MyApp',
theme: new ThemeData(
primarySwatch: Colors.orange),
home: new MainPage());
}
}
Page State code is where things will change.
We know Flutter provides Scaffold.of(context).showSnackBar
. However, the context should be the context of a descendant of a Scaffold, and not the context that includes a Scaffold. In order to avoid error, we need to use a BuildContext for the body of the Scaffold, and store it in a variable, as below.
class MainPageState extends State<MainPage> {
BuildContext scaffoldContext;
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.grey,
appBar: new AppBar(
title: const Text(APP_TITLE),
),
body: new Builder(builder: (BuildContext context) {
scaffoldContext = context;
return new Center(
child: new Text('Hello World', style: new TextStyle(fontSize: 32.0)),
);
}));
}
void createSnackBar(String message) {
final snackBar = new SnackBar(content: new Text(message),
backgroundColor: Colors.red);
// Find the Scaffold in the Widget tree and use it to show a SnackBar!
Scaffold.of(scaffoldContext).showSnackBar(snackBar);
}
}
Now, you can call this function from anywhere and it will display the Snackbar. For example, I am using it to display Internet Connectivity messages.
Solution 4
ScaffoldState
is now deprecated. Use ScaffoldMessengerState
.
There are generally two ways of showing the SnackBar
using ScaffoldMessenger
.
Direct way:
@override Widget build(BuildContext context) { return Scaffold( body: ElevatedButton( onPressed: () { var snackBar = SnackBar(content: Text('Hello World')); ScaffoldMessenger.of(context).showSnackBar(snackBar); }, child: Text('Show SnackBar'), ), ); }
Using
GlobalKey
.final _globalKey = GlobalKey<ScaffoldMessengerState>(); @override Widget build(BuildContext context) { return ScaffoldMessenger( key: _globalKey, child: Scaffold( body: Center( child: ElevatedButton( onPressed: () { var snackBar = SnackBar(content: Text('Hello World')); _globalKey.currentState.showSnackBar(snackBar); }, child: Text('Show SnackBar'), ), ), ), ); }
Solution 5
you can use this :
final _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
),
}
}
and then
in onPressed()
can add this code
_scaffoldKey.currentState.showSnackBar(
new SnackBar(
content: new Text('Hello this is snackbar!')
)
);
kosiara - Bartosz Kosarzycki
I'm a senior Java/Android developer constantly developing his skills more here: https://sites.google.com/site/bkosarzyckiaboutme/
Updated on July 05, 2022Comments
-
kosiara - Bartosz Kosarzycki almost 2 years
I want to display a simple SnackBar inside Flutter's stateful widget. My application creates new instance of MaterialApp with a stateful widget called MyHomePage.
I try to show the SnackBar in showSnackBar() method. But it fails with 'The method 'showSnackBar' was called on null'.
What's wrong with this code?
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter', theme: new ThemeData( primarySwatch: Colors.blue, ), home: new MyHomePage(), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key}) : super(key: key); @override _MyHomePageState createState() => new _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); @override void initState() { super.initState(); showInSnackBar("Some text"); } @override Widget build(BuildContext context) { return new Padding( key: _scaffoldKey, padding: const EdgeInsets.all(16.0), child: new Text("Simple Text") ); } void showInSnackBar(String value) { _scaffoldKey.currentState.showSnackBar(new SnackBar( content: new Text(value) )); } }
SOLUTION:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter', theme: new ThemeData( primarySwatch: Colors.blue, ), home: new Scaffold(body: new MyHomePage()), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key}) : super(key: key); @override _MyHomePageState createState() => new _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { showInSnackBar("Some text"); return new Padding( padding: const EdgeInsets.all(16.0), child: new Scaffold( body: new Text("Simple Text") ) ); } void showInSnackBar(String value) { Scaffold.of(context).showSnackBar(new SnackBar( content: new Text(value) )); } }
-
kosiara - Bartosz Kosarzycki over 7 yearssimply moving the
method showInSnackBar()
to build() does NOT help. On one hand you're right - initState() is called before the build() method, but even after initState() methods:Scaffold.of(context)
as well as field_scaffoldKey.currentState
are null. -
kosiara - Bartosz Kosarzycki over 7 yearswrapping my StatefulWidget with a new
Scaffold
and usingScaffold.of(context)
instead of the_scaffoldKey
reference helps. Thanks! -
Westy92 over 5 yearsHaving nested
Scaffold
s is strongly discouraged, so be careful here! -
Tokenyet almost 5 years@Westy92, It's interesting comments, could you please show us why? I have seen someone encouraged to use scaffold wrapping every widget, but I don't believe, tho.
-
Westy92 almost 5 years@Tokenyet github.com/flutter/flutter/pull/26259/…
-
Kirill Karmazin over 4 yearsHow this one is better than approach with GlobalKey provided by @Jack the Ripper?
-
Rohan Taneja about 4 yearsThe Flutter documentation describes this as "A less elegant but more expedient solution..". Please tread carefully :) Source: github.com/flutter/flutter/blob/master/packages/flutter/lib/src/…
-
live-love about 4 yearsBecause GlobalKey is expensive. See this answer there: stackoverflow.com/questions/51304568/…
-
Ashwin Balani over 3 yearsThat's the perfect use case for ScaffoldKey!
-
CopsOnRoad over 3 yearsHi, I've already written this in my answer. There's no benefit in adding the same thing twice.
-
Ezaldeen sahb over 3 yearsIf I saw your answer in the time I wrote this, I wouldn't waste my time writing a duplicate answer. have a nice day
-
CopsOnRoad over 3 yearsI just remove the
Builder
from my answer in the edit. Rest of the things are exactly the same, isn't it?