Scaffold.of() called with a context that does not contain a Scaffold
Solution 1
This exception happens because you are using the context
of the widget that instantiated Scaffold
. Not the context
of a child of Scaffold
.
You can solve this by just using a different context :
Scaffold(
appBar: AppBar(
title: Text('SnackBar Playground'),
),
body: Builder(
builder: (context) =>
Center(
child: RaisedButton(
color: Colors.pink,
textColor: Colors.white,
onPressed: () => _displaySnackBar(context),
child: Text('Display SnackBar'),
),
),
),
);
Note that while we're using Builder
here, this is not the only way to obtain a different BuildContext
.
It is also possible to extract the subtree into a different Widget
(usually using extract widget
refactor)
Solution 2
You can use a GlobalKey
. The only downside is that using GlobalKey might not be the most efficient way of doing this.
A good thing about this is that you can also pass this key to other custom widgets class that do not contain any scaffold. See(here)
class HomePage extends StatelessWidget {
final _scaffoldKey = GlobalKey<ScaffoldState>(); \\ new line
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey, \\ new line
appBar: AppBar(
title: Text('SnackBar Playground'),
),
body: Center(
child: RaisedButton(
color: Colors.pink,
textColor: Colors.white,
onPressed: _displaySnackBar(context),
child: Text('Display SnackBar'),
),
),
);
}
_displaySnackBar(BuildContext context) {
final snackBar = SnackBar(content: Text('Are you talkin\' to me?'));
_scaffoldKey.currentState.showSnackBar(snackBar); \\ edited line
}
}
Solution 3
You can solve this problem in two ways:
1) Using Builder widget
Scaffold(
appBar: AppBar(
title: Text('My Profile'),
),
body: Builder(
builder: (ctx) => RaisedButton(
textColor: Colors.red,
child: Text('Submit'),
onPressed: () {
Scaffold.of(ctx).showSnackBar(SnackBar(content: Text('Profile Save'),),);
}
),
),
);
2) Using GlobalKey
class HomePage extends StatelessWidget {
final globalKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: globalKey,
appBar: AppBar(
title: Text('My Profile'),
),
body: RaisedButton(
textColor: Colors.red,
child: Text('Submit'),
onPressed: (){
final snackBar = SnackBar(content: Text('Profile saved'));
globalKey.currentState.showSnackBar(snackBar);
},
),
);
}
}
Solution 4
UPDATE - 2021
Scaffold.of(context)
is deprecated in favor ofScaffoldMessenger
.
Check this from the documentation of method:
The ScaffoldMessenger now handles SnackBars in order to persist across routes and always be displayed on the current Scaffold. By default, a root ScaffoldMessenger is included in the MaterialApp, but you can create your own controlled scope for the ScaffoldMessenger to further control which Scaffolds receive your SnackBars.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo')
),
body: Builder(
// Create an inner BuildContext so that the onPressed methods
// can refer to the Scaffold with Scaffold.of().
builder: (BuildContext context) {
return Center(
child: RaisedButton(
child: Text('SHOW A SNACKBAR'),
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Hello!'),
));
},
),
);
},
),
);
}
You can check the detailed deprecation and new approach here:
Solution 5
Simple way to solving this issue will be creating a key for your scaffold like this final with the following code:
First: GlobalKey<ScaffoldState>() _scaffoldKey = GlobalKey<ScaffoldState>
();
Scecond: Assign the Key to your Scaffold key: _scaffoldKey
Third: Call the Snackbar using
_scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Welcome")));
Figen Güngör
Updated on December 26, 2021Comments
-
Figen Güngör over 2 years
As you can see, my button is inside the
Scaffold
's body. But I get this exception:Scaffold.of() called with a context that does not contain a Scaffold.
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: HomePage(), ); } } class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('SnackBar Playground'), ), body: Center( child: RaisedButton( color: Colors.pink, textColor: Colors.white, onPressed: _displaySnackBar(context), child: Text('Display SnackBar'), ), ), ); } } _displaySnackBar(BuildContext context) { final snackBar = SnackBar(content: Text('Are you talkin\' to me?')); Scaffold.of(context).showSnackBar(snackBar); }
EDIT:
I found another solution to this problem. If we give the
Scaffold
a key which is theGlobalKey<ScaffoldState>
, we can display the SnackBar as following without the need to wrap our body within theBuilder
widget. The widget which returns theScaffold
should be a Stateful widget though._scaffoldKey.currentState.showSnackBar(snackbar);
-
CodeGrue almost 6 yearsI thought with .of(context) it's supposed to travel up the widget hierarchy until it encounters one of the given type, in this case, Scaffold, which it should encounter before it reaches "Widget build(..". Does it not work this way?
-
CopsOnRoad over 5 years@RémiRousselet, How many types of context are there in Flutter? Like you said context of widget, context of a child of Scaffold.
-
Rémi Rousselet over 5 years@CopsOnRoad Only one. Scaffold is a widget too.
-
jbg over 5 years@CodeGrue it does work that way, but the
context
being passed toScaffold.of()
was "above" theScaffold
in the hierarchy, since it was the context passed toHomePage.build()
-
temirbek about 5 yearsthe code from question is same as the official docs (flutter.dev/docs/cookbook/design/snackbars) which doesn't use Builder, is it a bug in offical documentation?
-
Rémi Rousselet about 5 years
Builder
is not the only way obtain a differentBuildContext
. -
stevenspiel almost 5 years@RémiRousselet What are other ways to obtain a different BuildContext? I can think of using GlobalKeys, but what are some more?
-
Rémi Rousselet almost 5 yearsSplit your widget into multiple ones.
-
ExactaBox over 4 yearsCan I ask how to replicate this when your tree is comprised of multiple widgets defined in multiple files?
_scaffoldKey
is private due to the leading underscore. But even if it weren't, it is inside theHomePage
class and therefore unavailable without instantiating a new HomePage somewhere down the tree, seemingly creating a circular reference. -
ExactaBox over 4 yearsto answer my own question: create a singleton class with a
GlobalKey<ScaffoldState>
property, edit the constructor of the Widget with the scaffold to set the singleton's key property, then in the child widget's tree we can call something likemySingleton.instance.key.currentState.showSnackBar()
... -
user2233706 about 4 yearsWhy is this inefficient?
-
Lebohang Mbele about 4 years
-
Pankaj over 3 years
_scaffoldKey.currentState.showSnackBar(snackBar);
has been depreciated. -
Pankaj over 3 yearsBoth approached have been depreciated.
-
Pankaj over 3 yearsBoth approached have been depreciated
-
Keith DC almost 3 years@Pankaj Would you happen to have a source on both of these being deprecated? The
Builder
widget class is the top accepted answer, and the 2nd top answer usesGlobalKey
(which has been noted can be "expensive" as well as a reactive antipattern). And although this answer appears redundant to the top two answers, I can't seem to find a reference to either being deprecated. Thanks for any insights. -
Keith DC almost 3 yearsFor the first solution, I do know
Scaffold.of(context).showSnackBar(mySnackBar);
has been replaced byScaffoldMessenger.of(context).showSnackBar(mySnackBar);
. Is that what you were referring to with solution 1 being deprecated? EDIT: Oh! Is this why? "...In this case, the Builder is no longer required to provide a new scope with a BuildContext that is 'under' the Scaffold." -
Keith DC almost 3 yearsNever mind. I found the extended answer by @Deczaloth below. Glad I caught your comment though.
-
Keith DC almost 3 yearsRegarding deprecation: see this answer by @Deczaloth. The new approach calls on the
ScaffoldMessenger
to show the SnackBar. -
Keith DC almost 3 yearsFor an updated approach, see this answer by @Deczaloth. "The new approach calls on the
ScaffoldMessenger
to show the SnackBar. In this case, theBuilder
is no longer required to provide a new scope with a BuildContext that is 'under' the Scaffold." -
Keith DC almost 3 yearsRegarding deprecation: see this answer by @Deczaloth. "The new approach calls on the
ScaffoldMessenger
to show the SnackBar. -
Vipin Krishna about 2 yearsdo not forget to add : 'drawer: NavigationDrawer()'