Reputation: 1467
I am having trouble understanding the differences between the Widget BuildContext
and the Builder BuildContext
as of the following code snippets:
@override
Widget build(BuildContext context) {
and
new Builder(
builder: (BuildContext context){
By using the Widget BuildContext
the SnackBar doesn't appear in the UI but an error is shown in the logs which indicates that the Scaffold.of() Context
doesn't have a Scaffold while using the Builder context
everything worked fine.
Scaffold.of(context).showSnackBar(
new SnackBar(content: new Text('Processing Data')));
Edit: The main.dart file:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'APP'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final formKey = new GlobalKey<FormState>();
String username;
@override
//This context
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
body: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Flexible(
child: new Container(
child: new Center(
child: new Text(widget.title),
),
),
flex: 1,
),
new Form(
key: formKey,
child:
new Row(children: <Widget>[
new Flexible(child:
new Container(
margin: EdgeInsets.zero,
child: new TextFormField(
decoration:
new InputDecoration(
hintText: 'Username',
labelText: "1",
labelStyle: new TextStyle(color: new Color.fromARGB(255, 0, 0, 0)),
),
validator: (val) => val.isEmpty? 'Username can\'t be empty.' : null,
),
),
flex: 1,
),
new Flexible(child:
new Container(
margin: EdgeInsets.only(
left: 8.0,
right: 8.0,
),
child: new TextFormField(
decoration: new InputDecoration(
border: InputBorder.none,
hintText: "Password",
),
validator: (val) => val.isEmpty? 'Password can\'t be empty.' : null,
obscureText: true,
),
),
flex: 1,
),
new Container(
child:
new Builder(
//And this context
builder: (BuildContext context){
return RaisedButton(
child: new Text("Sign in"),
onPressed: (){
if (formKey.currentState.validate()) {
// If the form is valid, display a snackbar. In the real world, you'd
// often want to call a server or save the information in a database
Scaffold.of(context).showSnackBar(
new SnackBar(content: new Text('Processing Data')));
}
},
);
},
),
),
],
),
),
],
),
),
);
}
}
Upvotes: 1
Views: 2683
Reputation: 53307
It is better if you reference the current Scaffold
where you want the SnackBar
to appear in by using they key
property.
final GloabalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>();
Scaffold(
key:_key,
...
)
show the snack bar
_key.currentState.showSnackBar(mySnackBar)
Note that each builder method gets a context
to be able to reference it when using widgets that needs access to this context. In your code, the context
is being confused, if you change your build
method context
to be something unique like (Buildcontext scaffoldContext)
and then use Scaffold.of(scaffoldContext)
I am not sure if this will work as I see this confusion by in Flutter quite often.
Anyway the solution above is way cleaner.
Upvotes: 3