Reputation: 11802
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)
));
}
}
Upvotes: 85
Views: 196174
Reputation: 9
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: "pressed".text.make(),
));
},
Upvotes: 0
Reputation: 4299
We can use like this
**
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Enter your phone number"),
),
);
**
Upvotes: 4
Reputation: 1420
ScaffoldMessenger.of(context)
.showSnackBar(new SnackBar(content: Text('SnackBar Message')));
Upvotes: 0
Reputation: 21
use this package snackbar
customsnackbar: ^0.0.1
showCustomSnackBar("Hello", 10.0 ,5, Colors.white);
Upvotes: 0
Reputation: 20229
If you are inside a widget that does not has directly the return Scaffold(...)
widget, you can do this:
Scaffold.of(context).showSnackBar(SnackBar(content: Text("Hello from snackbar")));
There is no need to create an extra Scaffold widget because the showSnackBar()
method requires one, you can reuse.
Upvotes: 1
Reputation: 133
Scaffold.Of(context)
is deprecated for showing snackbar.
use the new way:
final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
Upvotes: 6
Reputation: 354
In the null safety version--
class _testPageState extends State<testPage> {
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SizedBox(
child: Scaffold(
key: _scaffoldKey,
body: Center(
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
onPressed: () {
final snackBar = SnackBar(content: Text('Your Text'));
_scaffoldKey.currentState!.showSnackBar(snackBar);
},
child: Text("Show SB"),
)
)
)
)
);
}
}
Upvotes: 0
Reputation: 1420
Display SnackBar in Flutter
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Please Enter Valid Data'),
backgroundColor: Colors.red,
));
Example:
if(value.isNotEmpty && value != null){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Validated Successfully'),
backgroundColor: Colors.green,
));
}else{
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Please Enter Valid Data'),
backgroundColor: Colors.red,
));
}
Upvotes: 2
Reputation: 268404
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'),
),
),
),
);
}
Upvotes: 45
Reputation: 739
ScaffoldState is now deprecated. Use ScaffoldMessengerState.
All the above solutions are amazing but as it's deprecated now you should use it this way.
var snackBar = SnackBar(content: Text('Hello World'));
ScaffoldMessenger.of(_scaffoldKey.currentContext)
.showSnackBar(snackBar );
Upvotes: 4
Reputation: 649
The best way is to create a PageWrapper that you can wrap all of your pages to get the context of the Scaffold widget and avoid experiencing these errors again.
Here is a sample of the page wrapper:
import 'package:flutter/material.dart';
class PageWrapper extends StatelessWidget {
Widget page;
WPage(this.page);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: page
);
}
}
Then you can wrap all your pages in the main.dart like these:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
initialRoute: '/login',
routes: {
'/login': (context) => PageWrapper(Login()),
'/home': (context) => PageWrapper(Home())
}
));
Now you can call Scaffold.of(context)
anywhere in any page just fine.
Reference: https://noobieprogrammer.blogspot.com/2020/06/how-to-create-error-alert-or-popup.html
or watch the video version (5 min. long): https://youtu.be/u9KoFtu0HEY
Upvotes: 1
Reputation: 3156
You can do this in three simple steps.
Make sure you have a key for scaffold. You can create that by writing the below code:
final _scaffoldKey = GlobalKey<ScaffoldState>();
2.Now you have to mention this key inside your Scaffold, by writing the below line inside scaffold:
key:_scaffoldKey,
Now you can show snackbar by writing:
final snackBar=SnackBar(
content: Text('Your password has been changed successfully'),
);
_scaffoldKey.currentState.showSnackBar(snackBar);
Upvotes: 4
Reputation: 76353
initState
been called before build
I guess _scaffoldKey.currentState
has not been initialized when it is call.
I don't know if you can get a ScaffoldState
from initState
. If you change your code you can show the snackbar from build
method with:
Scaffold.of(context).showSnackBar(SnackBar(Text(value)));
Upvotes: 7
Reputation: 141
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!')
)
);
Upvotes: 14
Reputation: 3889
Scaffold.of(context).showSnackBar(
SnackBar(content: Text("Thanks for using snackbar",
textAlign: TextAlign.center, style: TextStyle(fontSize: 16.0, fontWeight:
FontWeight.bold),), duration: Duration(seconds: 2), backgroundColor: Colors.red,)
);
Upvotes: 11
Reputation: 164
To initialise a Snackbar on initState() you can execute a function after the layout is built.
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Your message here..")));}
Upvotes: 10
Reputation: 3248
In case someone is looking to initialise a Snackbar
on initState()
(in other words when the page loads here is my solution). Also, I assume you already have the _scaffoldKey
in place.
void initState() {
super.initState();
Future.delayed(Duration(seconds: 1)).then(
(_) => _displaySnackbar
);
}
// Display Snackbar
void get _displaySnackbar {
_scaffoldKey.currentState.showSnackBar(SnackBar(
duration: Duration(minutes: 1),
content: Text('Your snackbar message')
));
}
Upvotes: 4
Reputation: 4415
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.
Upvotes: 33
Reputation: 6090
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 :)
Upvotes: 77
Reputation: 8609
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
.
Upvotes: 54