Fig*_*gör 91 scaffold snackbar flutter
你可以看到我的按钮在Scaffold的体内.但是我得到了这个例外:
Scaffold.of()使用不包含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);
}
Run Code Online (Sandbox Code Playgroud)
编辑:
我发现了另一个解决这个问题的方法.如果我们为Scaffold提供一个GlobalKey键,我们可以将SnackBar显示为以下内容,而无需使用Builder小部件包裹我们的主体.返回Scaffold的小部件应该是有状态的小部件:
_scaffoldKey.currentState.showSnackBar(snackbar);
Run Code Online (Sandbox Code Playgroud)
Rém*_*let 126
发生这种情况是因为您正在使用context
实例化的窗口小部件Scaffold
.不是context
孩子的Scaffold
.
您只需使用不同的上下文即可解决此问题:
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'),
),
),
),
);
Run Code Online (Sandbox Code Playgroud)
Leb*_*ele 62
你可以使用GlobalKey
.唯一的缺点是使用GlobalKey可能不是最有效的方法.
关于这一点的一个好处是,您还可以将此密钥传递给不包含任何支架的其他自定义窗口小部件类.见(这里)
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
}
Run Code Online (Sandbox Code Playgroud)
Dec*_*oth 15
(就历史价值而言,我还进一步低于我的原始答案......)
现在...输入...
从我们阅读的文档中
Scaffold 中的 SnackBar API 现在由 ScaffoldMessenger 处理,其中之一在 MaterialApp 的上下文中默认可用
因此,现在使用全新的ScaffoldMessenger,您将能够编写如下代码
Scaffold(
key: scaffoldKey,
body: GestureDetector(
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text('snack'),
duration: const Duration(seconds: 1),
action: SnackBarAction(
label: 'ACTION',
onPressed: () { },
),
));
},
child: const Text('SHOW SNACK'),
),
);
Run Code Online (Sandbox Code Playgroud)
现在,再次在文档中我们可以看到
在过渡期间呈现 SnackBar 时,SnackBar 会完成一个 Hero 动画,平滑地移动到下一页。
ScaffoldMessenger 创建了一个作用域,所有后代 Scaffolds 在其中注册以接收 SnackBars,这就是它们在这些转换中持久化的方式。当使用 MaterialApp 提供的根 ScaffoldMessenger 时,所有后代 Scaffolds 都会收到 SnackBars,除非在树的更下方创建新的 ScaffoldMessenger 作用域。通过实例化您自己的 ScaffoldMessenger,您可以控制哪些 Scaffolds 接收 SnackBars,哪些不基于您的应用程序的上下文。
您所遇到的这种行为甚至在Flutter 文档中被称为“棘手案例” 。
正如您可以从此处发布的其他答案中看到的那样,该问题已以不同方式解决。例如,我参考的那篇文档通过使用Builder
创建的a 解决了这个问题
一个内部,
BuildContext
以便onPressed
方法可以引用Scaffold
withScaffold.of()
。
因此,showSnackBar
从Scaffold调用的方法是
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Demo')),
body: Builder(
builder: (BuildContext innerContext) {
return FlatButton(
child: Text('BUTTON'),
onPressed: () {
Scaffold.of(innerContext).showSnackBar(SnackBar(
content: Text('Hello.')
));
}
);
}
)
);
}
Run Code Online (Sandbox Code Playgroud)
我自己发现通过简单地 ( Android Studio ) 将光标设置在一段代码(Flutter类、方法等)上并按 ctrl+B 以显示该特定部分的文档,我自己发现探索Flutter文档非常有指导意义。
BuildContext的文档中提到了您面临的特定问题,可以在其中阅读
每个小部件都有自己的BuildContext,它成为 [...].build 函数返回的小部件的父级。
因此,这意味着在我们的案例中,上下文 将是创建时我们的 Scaffold 小部件的父级(!)。此外,Scaffold.of的文档说它返回
来自包含给定上下文的此类的最近 [ Scaffold ] 实例的状态。
但是在我们的例子中,上下文没有(还)包含一个脚手架(它还没有被构建)。Builder在那里开始行动了!
文档再一次照亮了我们。在那里我们可以阅读
[Builder 类,很简单] 一个柏拉图式的小部件,它调用一个闭包来获取它的子小部件。
嘿,等一下,什么!?好吧,我承认:这并没有多大帮助......但足以说(遵循另一个 SO 线程)
Builder类的目的只是构建和返回子小部件。
所以现在一切都清楚了!通过在Scaffold 中调用Builder,我们正在构建 Scaffold 以便能够获得它自己的上下文,并且有了这个innerContext我们最终可以调用Scaffold.of(innerContext)
上面代码的注释版本如下
@override
Widget build(BuildContext context) {
// here, Scaffold.of(context) returns null
return Scaffold(
appBar: AppBar(title: Text('Demo')),
body: Builder(
builder: (BuildContext innerContext) {
return FlatButton(
child: Text('BUTTON'),
onPressed: () {
// here, Scaffold.of(innerContext) returns the locally created Scaffold
Scaffold.of(innerContext).showSnackBar(SnackBar(
content: Text('Hello.')
));
}
);
}
)
);
}
Run Code Online (Sandbox Code Playgroud)
Cop*_*oad 10
ScaffoldMessenger
(推荐)var snackBar = SnackBar(content: Text('Hi there'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
Run Code Online (Sandbox Code Playgroud)
Builder
或GlobalKey
)Scaffold(
body: ElevatedButton(
onPressed: () {
var snackBar = SnackBar(content: Text('Hello World'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
child: Text('Show SnackBar'),
),
)
Run Code Online (Sandbox Code Playgroud)
Bam*_*oUA 10
从 Flutter 版本 1.23-18.1.pre 开始,您可以使用 ScaffoldMessenger
final mainScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
class Main extends StatelessWidget {
@override
Widget build(BuildContext) {
return MaterialApp(
...
scaffoldMessengerKey: mainScaffoldMessengerKey
...
);
}
}
Run Code Online (Sandbox Code Playgroud)
应用程序内的某处:
mainScaffoldMessengerKey.currentState.showSnackBar(Snackbar(...));
Run Code Online (Sandbox Code Playgroud)
从方法文档中进行检查:
当实际上在同一构建函数中创建了脚手架时,该构建函数的context参数不能用于找到该脚手架(因为它在返回的小部件“上方”)。在这种情况下,可以使用以下带有Builder的技术来为BuildContext提供“在”脚手架下方的新作用域:
@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: () {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('Hello!'),
));
},
),
);
},
),
);
}
Run Code Online (Sandbox Code Playgroud)
您可以从docs 方法中查看说明
解决此问题的简单方法是使用以下代码为脚手架创建密钥,如最终版本:
第一: GlobalKey<ScaffoldState>() _scaffoldKey = GlobalKey<ScaffoldState>
();
第二步:将密钥分配给您的支架 key: _scaffoldKey
第三:使用
_scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Welcome")));
更有效的解决方案是将构建功能拆分为多个小部件。这引入了一个“新上下文”,您可以从中获取 Scaffold
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Scaffold.of example.')),
body: MyScaffoldBody(),
),
);
}
}
class MyScaffoldBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text('Show a snackBar'),
onPressed: () {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Have a Snack'),
),
);
}),
);
}
}
Run Code Online (Sandbox Code Playgroud)
有两种方法可以解决此问题
1)使用构建器小部件
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'),
),
),
),
);
Run Code Online (Sandbox Code Playgroud)
2)使用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: showSnackbar(context),
),
),
);
}
}
void showSnackbar(BuildContext context) {
final snackBar = SnackBar(content: Text('Profile saved'));
globalKey.currentState.showSnackBar(snackBar);
}
Run Code Online (Sandbox Code Playgroud)
我可能会迟到。但这也会对某人有所帮助。在Scaffold下添加一个_key。然后使用该_key调用openDrawer方法。
return Scaffold(
key: _scaffoldKey, //this is the key
endDrawer: Drawer(),
appBar: AppBar(
//all codes for appbar here
actions: [
IconButton(
splashRadius: 20,
icon: Icon(Icons.settings),
onPressed: () {
_scaffoldKey.currentState.openEndDrawer(); // this is it
},
),]
Run Code Online (Sandbox Code Playgroud)
我不会费心使用默认的snackbar,因为您可以导入flushbar包,这可以实现更大的可定制性:
https://pub.dev/packages/flushbar
例如:
Flushbar(
title: "Hey Ninja",
message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry",
duration: Duration(seconds: 3),
)..show(context);
Run Code Online (Sandbox Code Playgroud)
小智 5
也许这段代码中有一个解决方案。
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("SnackBar Message")));
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
25877 次 |
最近记录: |