我想在Flutter 的有状态小部件中显示一个简单的SnackBar。我的应用程序使用名为 MyHomePage 的有状态窗口小部件创建 MaterialApp 的新实例。
我尝试在showSnackBar()方法中显示SnackBar。但它失败了'方法'showSnackBar'被调用为null '。
这段代码出了什么问题?
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@override
void initState() {
super.initState();
showInSnackBar("Some text");
}
@override
Widget build(BuildContext context) {
return new Padding(
key: _scaffoldKey,
padding: const EdgeInsets.all(16.0),
child: new Text("Simple Text")
);
}
void showInSnackBar(String value) {
_scaffoldKey.currentState.showSnackBar(new SnackBar(
content: new Text(value)
));
}
}
SOLUTION:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(body: new MyHomePage()),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
showInSnackBar("Some text");
return new Padding(
padding: const EdgeInsets.all(16.0),
child: new Scaffold(
body: new Text("Simple Text")
)
);
}
void showInSnackBar(String value) {
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text(value)
));
}
}
答案 0 :(得分:27)
有三个问题。首先,您不会在任何地方拥有脚手架,而脚手架小部件则是知道如何显示小吃店的小部件。第二个是你有一把钥匙可以抓住脚手架,但是你已经把它放在Padding上了(Paddings不知道小吃店)。第三个是你在与它关联的小部件之前使用了密钥有机会被初始化,因为在构建之前调用了initState。
最简单的解决方案是将MyApp小部件中的home
行更改为:
home: new Scaffold(body: new MyHomePage()),
...然后删除所有提及的_scaffoldKey
,而使用Scaffold.of(context)
,而您当前拥有_scaffoldKey.currentState
。
答案 1 :(得分:10)
在我的情况下,我有这样的代码(在类州)
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
void showInSnackBar(String value) {
_scaffoldKey.currentState.showSnackBar(new SnackBar(content: new Text(value)));
}
但我没有设置脚手架的钥匙。 所以当我添加键:_scaffoldKey
时 @override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
body: new SafeArea(
snackbar开始工作:)
答案 2 :(得分:8)
有一种更好更清洁的方式来显示颤动的Snackbar。我发现它很难分享,所以也许对其他人有帮助。
无需更改主应用部分
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'MyApp',
theme: new ThemeData(
primarySwatch: Colors.orange),
home: new MainPage());
}
}
页面状态代码是事物发生变化的地方。
我们知道Flutter提供Scaffold.of(context).showSnackBar
。但是,上下文应该是脚手架后代的上下文,而不是包含脚手架的上下文。为了避免错误,我们需要为Scaffold的主体使用BuildContext,并将其存储在变量中,如下所示。
class MainPageState extends State<MainPage> {
BuildContext scaffoldContext;
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.grey,
appBar: new AppBar(
title: const Text(APP_TITLE),
),
body: new Builder(builder: (BuildContext context) {
scaffoldContext = context;
return new Center(
child: new Text('Hello World', style: new TextStyle(fontSize: 32.0)),
);
}));
}
void createSnackBar(String message) {
final snackBar = new SnackBar(content: new Text(message),
backgroundColor: Colors.red);
// Find the Scaffold in the Widget tree and use it to show a SnackBar!
Scaffold.of(scaffoldContext).showSnackBar(snackBar);
}
}
现在,您可以从任何地方调用此函数,它将显示Snackbar。例如,我用它来显示Internet连接消息。
答案 3 :(得分:4)
ScaffoldState
现在已弃用。使用ScaffoldMessengerState
。通常有两种使用SnackBar
显示ScaffoldMessenger
的方式。
直接方法:
@override
Widget build(BuildContext context) {
return Scaffold(
body: RaisedButton(
onPressed: () {
var snackBar = SnackBar(content: Text('Hello World'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
child: Text('Show SnackBar'),
),
);
}
使用GlobalKey
。
final _globalKey = GlobalKey<ScaffoldMessengerState>();
@override
Widget build(BuildContext context) {
return ScaffoldMessenger(
key: _globalKey,
child: Scaffold(
body: Center(
child: RaisedButton(
onPressed: () {
var snackBar = SnackBar(content: Text('Hello World'));
_globalKey.currentState.showSnackBar(snackBar);
},
child: Text('Show SnackBar'),
),
),
),
);
}
答案 4 :(得分:3)
initState
之前调用了{p> build
我猜_scaffoldKey.currentState
在调用时尚未初始化。
我不知道你是否可以从ScaffoldState
获得initState
。如果您更改了代码,则可以使用build
方法显示小吃栏:
Scaffold.of(context).showSnackBar(new SnackBar(new Text(value)));
答案 5 :(得分:2)
万一有人想在Snackbar
上初始化initState()
(换句话说,当页面加载在这里是我的解决方案)。另外,我假设您已经安装了_scaffoldKey
。
void initState() {
super.initState();
Future.delayed(Duration(seconds: 1)).then(
(_) => _displaySnackbar
);
}
// Display Snackbar
void get _displaySnackbar {
_scaffoldKey.currentState.showSnackBar(SnackBar(
duration: Duration(minutes: 1),
content: Text('Your snackbar message')
));
}
答案 6 :(得分:2)
您可以使用:
final _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
),
}
}
然后
在onPressed()
中可以添加此代码
_scaffoldKey.currentState.showSnackBar(
new SnackBar(
content: new Text('Hello this is snackbar!')
)
);
答案 7 :(得分:2)
您可以通过三个简单的步骤来完成此操作。
确保您具有脚手架钥匙。您可以通过编写以下代码来创建该代码:
final _scaffoldKey = GlobalKey<ScaffoldState>();
2。现在,您必须在脚手架中提及此密钥,方法是在脚手架内编写以下行:
key:_scaffoldKey,
现在您可以通过显示以下内容显示小吃店:
final snackBar=SnackBar(
content: Text('Your password has been changed successfully'),
);
_scaffoldKey.currentState.showSnackBar(snackBar);
答案 8 :(得分:2)
Scaffold.Of(context) 已弃用以显示小吃店。
使用新方法:
somefunction
答案 9 :(得分:1)
我喜欢它,为我工作:)
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Demo')
),
body: new Builder(
// Create an inner BuildContext so that the onPressed methods
// can refer to the Scaffold with Scaffold.of().
builder: (BuildContext context) {
return new Center(
child: new RaisedButton(
child: new Text('SHOW A SNACKBAR'),
onPressed: () {
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text('Hello!'),
));
},
),
);
},
),
);
}
答案 10 :(得分:1)
要在initState()上初始化Snackbar,可以在构建布局后执行一个函数。
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Your message here..")));}
答案 11 :(得分:1)
**
**
以上所有解决方案都很了不起,但由于现在已过时,您应该以这种方式使用它。
var snackBar = SnackBar(content: Text('Hello World'));
ScaffoldMessenger.of(_scaffoldKey.currentContext)
.showSnackBar(snackBar );
答案 12 :(得分:0)
{% url %}
答案 13 :(得分:0)
打开小吃店有很多方法,但是我要说的是,有一种无需任何上下文即可打开小吃店并完全自定义它的方法,它可以使用颜色,模糊,形状,渐变,图标以及从字面上进行的任何操作通过此程序包:
代替传递上下文,而不是创建globalKey并将其附加到您的Scaffold上,您只需调用:Get.snackbar("Hi", "your message");
并准备好!
最有趣的是,您可以从任何地方调用小吃栏,例如,当API发生故障时,可以从控制器返回错误消息。
这是非常值得知道的。
答案 14 :(得分:0)
最好的方法是创建一个PageWrapper,您可以包装所有页面以获取Scaffold小部件的上下文,并避免再次遇到这些错误。
以下是页面包装程序的示例:
import 'package:flutter/material.dart';
class PageWrapper extends StatelessWidget {
Widget page;
WPage(this.page);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: page
);
}
}
然后,您可以将所有页面包装在main.dart中,如下所示:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
initialRoute: '/login',
routes: {
'/login': (context) => PageWrapper(Login()),
'/home': (context) => PageWrapper(Home())
}
));
现在,您可以在任意页面的任何地方调用Scaffold.of(context)
。
参考:https://noobieprogrammer.blogspot.com/2020/06/how-to-create-error-alert-or-popup.html
或观看视频版本(长5分钟):https://youtu.be/u9KoFtu0HEY
答案 15 :(得分:0)
如果您位于没有直接return Scaffold(...)
小部件的小部件中,则可以执行以下操作:
Scaffold.of(context).showSnackBar(SnackBar(content: Text("Hello from snackbar")));
无需创建额外的Scaffold小部件,因为showSnackBar()方法需要一个,即可重复使用。