无法显示SnackBar

时间:2019-04-06 17:46:45

标签: flutter

我是Flutter的新手,只是四处逛逛以了解此框架的工作原理。因此,下面的代码没有多大意义。

我正在尝试通过调用子小部件来在应用加载后立即显示小吃店。

这是代码:

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): The following assertion was thrown building GetSnackBarWidget(dirty): I/flutter ( 3781): setState() or markNeedsBuild() called during build. I/flutter ( 3781): This Scaffold widget cannot be marked as needing to build because the framework is already in the I/flutter ( 3781): process of building widgets. A widget can be marked as needing to be built during the build phase I/flutter ( 3781): only if one of its ancestors is currently building. This exception is allowed because the framework I/flutter ( 3781): builds parent widgets before children, which means a dirty descendant will always be built. I/flutter ( 3781): Otherwise, the framework might not visit this widget during this build phase. I/flutter ( 3781): The widget on which setState() or markNeedsBuild() was called was: I/flutter ( 3781): Scaffold(dependencies: [_LocalizationsScope-[GlobalKey#33728], Directionality, _InheritedTheme, I/flutter ( 3781): MediaQuery], state: ScaffoldState#dbc9e(tickers: tracking 2 tickers)) I/flutter ( 3781): The widget which was currently being built when the offending call was made was: I/flutter ( 3781): GetSnackBarWidget(dirty)

有人可以详细解释发生了什么事吗?

3 个答案:

答案 0 :(得分:0)

基本上,在构建窗口小部件时,不能直接调用Scaffold.of(context).showSnackBar(snackBar)。如果有按钮,则可以将其用于onPressed方法,因为在构建窗口小部件时不会立即调用它,而是在其他一些异步事件之后调用它。

如果您有一个快餐栏可以立即显示,则解决方案是告诉应用程序在构建完所有小部件后立即显示快餐栏。您可以通过使用WidgetsBinding.instance.addPostFrameCallback()来添加显示小吃店的回调方法来做到这一点,就像这样:

final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

...

    return Scaffold(
      key: _scaffoldKey,

...
         //when you want to display the snackbar during a build method, 
         //use addPostFrameCallback

         WidgetsBinding.instance.addPostFrameCallback((_) => _showMessage('snackbar message'));

...

void _showMessage(String message) {
  _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message),));
}

答案 1 :(得分:0)

首先,将SnackBar放入您的build()方法中不是一个好主意。您可以尝试根据需要在应用启动时显示SnackBar的解决方案。

class _HomePageState extends State<HomePage> {
  GlobalKey<ScaffoldState> _key = GlobalKey();

  @override
  void initState() {
    super.initState();
    Timer.run(() => _key.currentState.showSnackBar(SnackBar(content: Text("Hi"),)));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _key,
      appBar: AppBar(title: Text("App")),
      body: Container(),
    );
  }
}

答案 2 :(得分:0)

如果要在小部件中显示SnackBar,则必须遵循以下代码:

class _DelayWidgetState extends State<DelayWidget> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("SbackBar Functionality"),
      ),
      body: new Builder(builder: (BuildContext context) {
        return new RaisedButton(
          onPressed: () {
            Scaffold.of(context).showSnackBar(
              new SnackBar(
                content: new Text("Sending Message"),
              ),
            );
          },
          child: new Text("Click"),
        );
      }),
    );
  }
}

在上面的示例中,添加的另一个Builder作为Scaffold.of()调用,其上下文不包含Scaffold。