Pra*_*aik 18 flutter flutter-layout
我试图通过点击颤动中的按钮来创建一个小吃栏,但出现异常,找不到ScaffoldMessenger小部件。相同的代码似乎在文档中提到的 Flutter示例中可以正常工作。我在这里错过了什么吗?谢谢。
这是我的 main.dart 文件
\nimport \'package:flutter/material.dart\';\n\nvoid main() => runApp(MyAppWidget());\n\nclass MyAppWidget extends StatefulWidget {\n @override\n State<StatefulWidget> createState() {\n return _MyAppState();\n }\n}\n\nclass _MyAppState extends State<MyAppWidget> {\n final _inputKey = GlobalKey<FormState>();\n final _messangerKey = GlobalKey<ScaffoldMessengerState>();\n String inputText = "";\n\n String appendString() {\n setState(() {\n inputText += inputText;\n });\n return inputText;\n }\n\n @override\n Widget build(BuildContext context) {\n return MaterialApp(\n scaffoldMessengerKey: _messangerKey,\n home: Scaffold(\n appBar: AppBar(\n title: Text("Assignment"),\n ),\n body: Form(\n key: _inputKey,\n child: Column(\n children: [\n TextFormField(\n validator: (inputString) {\n inputText = inputString;\n if (inputString.length < 5) {\n return \'Please enter a longer string\';\n }\n return null;\n },\n ),\n ElevatedButton(\n onPressed: () {\n if (_inputKey.currentState.validate()) {\n ScaffoldMessenger.of(context).showSnackBar(\n SnackBar(content: Text(\'Processing Data\')));\n }\n },\n child: Text("Enter"),\n ),\n Text(appendString())\n ],\n ),\n ),\n ),\n );\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n这是我遇到的异常
\n\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90 Exception caught by gesture \xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\nThe following assertion was thrown while handling a gesture:\nNo ScaffoldMessenger widget found.\n\nMyAppWidget widgets require a ScaffoldMessenger widget ancestor.\n\nHandler: "onTap"\n\n#4 _InkResponseState._handleTap\npackage:flutter/\xe2\x80\xa6/material/ink_well.dart:991\n#3 _MyAppState.build.<anonymous closure>\npackage:assignment_1/main.dart:48\n#2 ScaffoldMessenger.of\npackage:flutter/\xe2\x80\xa6/material/scaffold.dart:224\n#1 debugCheckHasScaffoldMessenger\npackage:flutter/\xe2\x80\xa6/material/debug.dart:153\n#0 debugCheckHasScaffoldMessenger.<anonymous closure>\npackage:flutter/\xe2\x80\xa6/material/debug.dart:142\nWhen the exception was thrown, this was the stack\n\nTypically, the ScaffoldMessenger widget is introduced by the MaterialApp at the top of your application widget tree.\n\n renderObject: RenderView#a5074\n [root]\nThe ancestors of this widget were\n state: _MyAppState#a2cb9\nRestarted application in 691ms.\n\n\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90 Exception caught by gesture \xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\nThe following assertion was thrown while handling a gesture:\nNo ScaffoldMessenger widget found.\n\nMyAppWidget widgets require a ScaffoldMessenger widget ancestor.\nThe specific widget that could not find a ScaffoldMessenger ancestor was: MyAppWidget\n\nRun Code Online (Sandbox Code Playgroud)\n
Bak*_*ker 19
回答最初的问题:“我在这里缺少什么?”:
ScaffoldMessenger.of(context)正在使用contextnot Below(即不是其子项)MaterialApp。 (上面没有ScaffoldMessenger找到。)
本机 Flutter 静态方法<SomeClassName>.of(context)会沿着 widget 树查找InheritedWidget名为 的类型父级<SomeClassName>。ScaffoldMessenger.of(context)寻找父母也是如此ScaffoldMessenger。1
MaterialAppwidget 为我们提供了 aScaffoldMessenger因为它将它的子级包装在 a 中ScaffoldMessenger。MaterialApp's以下是“构建器”方法的摘录:
Widget _materialBuilder(BuildContext context, Widget? child) {
return ScaffoldMessenger( // <<<< <<<< hello Mr. ScaffoldMessenger
key: widget.scaffoldMessengerKey,
child: AnimatedTheme(
data: theme,
child: widget.builder != null
? Builder(
builder: (BuildContext context) {
return widget.builder!(context, child); // your kid
},
)
: child ?? const SizedBox.shrink(),
),
);
}
Run Code Online (Sandbox Code Playgroud)
上面的内容child可能是您提供给的最顶层的小部件MaterialApp。只有该小部件的构建方法及其以下版本才能在其父祖先中找到ScaffoldMessengerfrom 。MaterialApp
最初的问题.showSnackBar()是查找MyApp's上下文/父母祖先,而不是 MaterialApp's。
MyApp(context)
-> MaterialApp(gets MyApp context) + other Widget(gets MyApp context) (no ScaffoldMessenger avail!)
-> kids (gets MaterialApp context, thus ScaffoldMessenger above)
Run Code Online (Sandbox Code Playgroud)
我们使用的确实很容易出错context。
在原始代码片段中,我们使用context此级别最接近的可见项,即MyApp's
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) { // <<<< this MyApp context...
return MaterialApp(
scaffoldMessengerKey: _messangerKey,
home: Scaffold(
appBar: AppBar(
title: Text("Assignment"),
),
body: Form(
key: _inputKey,
child: Column(
children: [
TextFormField(
validator: (inputString) {
inputText = inputString;
if (inputString.length < 5) {
return 'Please enter a longer string';
}
return null;
},
),
ElevatedButton(
onPressed: () {
if (_inputKey.currentState.validate()) {
ScaffoldMessenger.of(context).showSnackBar( // is this context <<<
SnackBar(content: Text('Processing Data')));
}
Run Code Online (Sandbox Code Playgroud)
尽管Scaffold > Form > ElevatedButton小部件在物理上显示为“较低/下方” MaterialApp,但它们当前位于MyApp's build(BuildContext context)方法内,因此当前正在使用MyApp's context.
要使用 的上下文MaterialApp,需要从内部方法内部Scaffold/Form/ElevatedButton调用,从而获取其.build(BuildContext context) MaterialAppcontext
避免上述陷阱的一种方法是保持MyApp/MaterialApp非常简单,并从另一个层次开始编码,如下HomePage例所示:
class MyApp extends StatelessWidget {
const MyApp({Key? key, required this.bindings}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const HomePage(), // <<< put your stuff in HomePage's build() method
);
}
}
Run Code Online (Sandbox Code Playgroud)
或者,我们可以将home:小部件包装在Builder小部件(文档)中,然后其中的每个子部件Builder都将使用MaterialApp's context,其中第一个可用ScaffoldMessenger。
class MyApp extends StatelessWidget {
const MyApp({Key? key, required this.bindings}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(builder: (BuildContext context) {
// stuff here gets MaterialApp context
}),
);
}
}
Run Code Online (Sandbox Code Playgroud)
正如其他答案中提到的,我们可以使用scaffoldMessengerKeyarg,如迁移指南GlobalKey<ScaffoldMessengerState>中介绍的那样。ScaffoldMessenger
1 这个查找到的类型其实是,里面包含了字段,就是提供我们感兴趣的API方法的对象,比如InheritedWidget.of()_ScaffoldMessengerScopeScaffoldMessengerStateSnackBar.showSnackBar()
Pra*_*aik 15
按照EngineSense的建议,创建了一个全局密钥
final _messangerKey = GlobalKey<ScaffoldMessengerState>();
Run Code Online (Sandbox Code Playgroud)
并将其添加到按钮的 onPressed 方法中
_messangerKey.currentState.showSnackBar(
SnackBar(content: Text('Processing Data')));
Run Code Online (Sandbox Code Playgroud)
以下是更新后的更改,供参考。
import 'package:flutter/material.dart';
void main() => runApp(MyAppWidget());
class MyAppWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyAppWidget> {
final _inputKey = GlobalKey<FormState>();
final _messangerKey = GlobalKey<ScaffoldMessengerState>();
String inputText = "";
String appendString() {
setState(() {
inputText += inputText;
});
return inputText;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
scaffoldMessengerKey: _messangerKey,
home: Scaffold(
appBar: AppBar(
title: Text("Assignment"),
),
body: Form(
key: _inputKey,
child: Column(
children: [
TextFormField(
validator: (inputString) {
inputText = inputString;
if (inputString.length < 5) {
return 'Please enter a longer string';
}
return null;
},
),
ElevatedButton(
onPressed: () {
if (_inputKey.currentState.validate()) {
_messangerKey.currentState.showSnackBar(
SnackBar(content: Text('Processing Data')));
}
},
child: Text("Enter"),
),
Text(appendString())
],
),
),
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
脚手架MessengerKey.currentState.showSnackBar(mySnackBar); 脚手架MessengerKey.currentState.hideCurrentSnackBar(mySnackBar); 脚手架MessengerKey.currentState.removeCurrentSnackBar(mySnackBar);
| 归档时间: |
|
| 查看次数: |
18931 次 |
| 最近记录: |