无法显示 SnackBar
无法显示 SnackBar
我是Flutter的新手,只是为了理解这个框架的工作原理而玩一下。所以下面的代码没有太多意义。
我想在应用程序加载时调用一个子小部件来显示一个snack bar。
以下是代码:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Demo')),
body: GetSnackBarWidget(),
),
);
}
}
class GetSnackBarWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final snackBar = SnackBar(content: Text("SnackBar"));
Scaffold.of(context).showSnackBar(snackBar);
return Text("returned");
}
}
但是我得到了以下异常:
I/flutter ( 3781): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 3781): GetSnackBarWidget(dirty)构建期间调用了setState()或markNeedsBuild()。
I/flutter ( 3781): 由于框架已经在构建小部件的过程中,因此无法将此Scaffold小部件标记为需要构建。
I/flutter ( 3781): 只有在某个祖先小部件当前正在构建时,才能在构建阶段将小部件标记为需要构建。这种情况下允许抛出此异常,因为框架
I/flutter ( 3781): 在构建子小部件之前会先构建父小部件,这意味着脏的后代小部件总是会被构建。
I/flutter ( 3781): 否则,在此构建阶段框架可能不会访问此小部件。
I/flutter ( 3781): 在调用setState()或markNeedsBuild()的小部件是:
I/flutter ( 3781): Scaffold(dependencies: [_LocalizationsScope-[GlobalKey#33728], Directionality, _InheritedTheme,
I/flutter ( 3781): MediaQuery], state: ScaffoldState#dbc9e(tickers: tracking 2 tickers))
I/flutter ( 3781): 在进行有问题调用时正在构建的小部件是:
I/flutter ( 3781): GetSnackBarWidget(dirty)
有人可以详细解释一下发生了什么吗?
"Unable to display SnackBar"问题的原因是在构建小部件时直接调用Scaffold.of(context).showSnackBar(snackBar)。如果有一个按钮,可以将其用作onPressed方法,因为它不会立即被调用,而是在某些其他异步事件之后。
解决方法是,如果一开始就要显示snackbar,则可以告诉应用程序在构建所有小部件完成后立即显示snackbar。可以使用WidgetsBinding.instance.addPostFrameCallback()添加一个回调方法来显示snackbar,如下所示:
final GlobalKey
...
return Scaffold(
key: _scaffoldKey,
...
//在构建方法中想要显示snackbar时,使用addPostFrameCallback
WidgetsBinding.instance.addPostFrameCallback((_) => _showMessage('snackbar message'));
...
void _showMessage(String message) {
_scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message),));
}
这个解决方法有效。如果我理解正确的话,问题是我在调用仍处于构建状态的小部件(Scaffold)。此外,你能否提供一些详细解释WidgetsBinding.instance.addPostFrameCallback和_scaffoldKey.currentState的链接。我尝试过很多搜索但没有找到。谢谢。
这里有一个类似的例子-stackoverflow.com/questions/51458885/…,这可能是我最初得到答案的地方。
无法显示SnackBar的原因是在上述示例中,Scaffold.of()调用了一个不包含Scaffold的上下文。解决方法是将Builder包装在Scaffold中。以下是修复后的代码示例:
class _DelayWidgetState extends State
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("SbackBar功能"),
),
body: new Scaffold(
body: new Builder(builder: (BuildContext context) {
return new RaisedButton(
onPressed: () {
Scaffold.of(context).showSnackBar(
new SnackBar(
content: new Text("发送消息"),
),
);
},
child: new Text("点击"),
);
}),
),
);
}
}
首先,将SnackBar放在build()方法中是一个不好的做法。你可以尝试下面的解决方案,在应用启动时显示SnackBar,正如你所需要的那样。
class _HomePageState extends State
GlobalKey
void initState() {
super.initState();
Timer.run(() => _key.currentState.showSnackBar(SnackBar(content: Text("Hi"),)));
}
Widget build(BuildContext context) {
return Scaffold(
key: _key,
appBar: AppBar(title: Text("App")),
body: Container(),
);
}
}
在这个解决方案中,我们创建了一个GlobalKey
这样,当应用启动时,SnackBar将立即显示出来,而不是等待build()方法被调用。这解决了无法显示SnackBar的问题,并确保SnackBar在应用启动时立即显示出来。