Reputation: 15726
android studio 3.6
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primaryColor: new Color(Constants.COLOR_PRIMARY),
primaryTextTheme: TextTheme(headline6: TextStyle(color: Colors.white))),
home: new SignInForm());
}
}
class SignInForm extends StatefulWidget {
@override
State<StatefulWidget> createState() {
logger.d("createState:");
return new _SignInFormState();
}
}
class _SignInFormState extends State {
final _formKey = GlobalKey<FormState>();
final _scaffoldKey = GlobalKey<ScaffoldState>();
String _textVersion = "";
String _email = null;
String _password = null;
@override
Widget build(BuildContext context) {
logger.d("build:");
//String _errorMessage = null;
return Scaffold(
appBar: new AppBar(
centerTitle: true,
title: new Text('Sign in',
style: TextStyle(fontWeight: FontWeight.bold))),
body: new Container(
margin: const EdgeInsets.only(
left: Constants.DEFAULT_MARGIN,
right: Constants.DEFAULT_MARGIN),
child: new Form(
key: _formKey,
child: new Column(children: [
new TextFormField(
decoration: new InputDecoration(hintText: 'Email'),
keyboardType: TextInputType.emailAddress,
onChanged: (value) {
setState(() {
_email = value;
});
}),
new TextFormField(
decoration: new InputDecoration(hintText: 'Password'),
obscureText: true),
new Container(
margin: const EdgeInsets.only(
top: Constants.DEFAULT_MARGIN / 2),
height: Constants.MIN_HEIGHT,
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Text("Forgot password?",
style: TextStyle(
color: new Color(Constants.COLOR_PRIMARY))),
new Align(
alignment: Alignment.centerRight,
child: new RaisedButton(
// Buttons are disabled by default
child: Text('Sign in'.toUpperCase()),
color: new Color(Constants.COLOR_PRIMARY),
textColor: new Color(
Constants.COLOR_PRIMARY_TEXT_COLOR),
onPressed: () {
if (_formKey.currentState.validate()) {
logger.d(
"onPressed: check_email = $_email");
if (_email == null ||
_email.trim().isEmpty) {
logger.d(
"onPressed: show_error_message");
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text("Аll fields must be filled"),
backgroundColor: Colors.red));
}
}
}))
])),
new Container(
margin: const EdgeInsets.all(Constants.DEFAULT_MARGIN),
child: new Text('Registration'.toUpperCase(),
style: new TextStyle(
color: new Color(Constants.COLOR_PRIMARY),
fontWeight: FontWeight.bold))),
new Container(
margin: const EdgeInsets.all(Constants.DEFAULT_MARGIN),
child: new Text(_textVersion))
]))));
}
press button and get error in in this line:
Scaffold.of(context).showSnackBar(
logcat:
The context used was: SignInForm
state: _SignInFormState#fe66a
When the exception was thrown, this was the stack:
#0 Scaffold.of (package:flutter/src/material/scaffold.dart:1456:5)
#1 _SignInFormState.build.<anonymous closure> (package:flutter_sample/signinform.dart:86:52)
#2 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:779:14)
#3 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:862:36)
#4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#74eb7
debugOwner: GestureDetector
state: possible
won arena
finalPosition: Offset(268.7, 208.0)
finalLocalPosition: Offset(52.7, 18.0)
button: 1
sent tap down
Upvotes: 0
Views: 65
Reputation: 107231
The issue happens because the current passed context doesn't have any matching ancestor (in this case a matching ancestor scaffold).
The easiest way to fix this issue is, in your MyApp, replace:
home: new SignInForm()
with:
home: Scaffold(body: SignInForm())
You have to specify the key property of your scaffold:
Scaffold(key: _scaffoldKey, body: // Your remaining code);
And display the snackbar using:
_scaffoldKey.currentState.showSnackBar(
SnackBar(content: Text("Аll fields must be filled"),
backgroundColor: Colors.red)
);
You can use a Builder widget to fix the issue:
Scaffold(body: Builder(builder: (context) {
return Container(child:// Your widget);
// No other change needed
},);
I personally prefer option 3.
When the Scaffold is actually created in the same build function, the context argument to the build function can't be used to find the Scaffold (since it's "above" the widget being returned in the widget tree).
Reference of method
Upvotes: 1