ScaffoldMessenger.of(context).showSnackBar() 在小部件构建函数中直接调用时不起作用

Posted

技术标签:

【中文标题】ScaffoldMessenger.of(context).showSnackBar() 在小部件构建函数中直接调用时不起作用【英文标题】:ScaffoldMessenger.of(context).showSnackBar() doesn't work when called directly inside a widget build function 【发布时间】:2021-10-03 03:02:18 【问题描述】:

在寻找使用颤振SnackBarScaffoldMessenger 的示例时,我只找到了onPressed 函数的用法:

    Widget build(BuildContext context) 
        return Container(
            child: ElevatedButton(
              child: ...,
              onPressed: () => _showToast(context),
            ));
      
    
      void _showToast(BuildContext context) 
        final scaffold = ScaffoldMessenger.of(context);
        scaffold.showSnackBar(
          SnackBar(content: const Text('Added to favorite')),
        );
      
    

但没有一个示例解释了为什么必须仅将它与 onPressed 一起使用, 所以我自己尝试并直接在构建函数中使用:

         Widget build(BuildContext context) 
           _showToast(context);   <---
           return Container(
              child: ElevatedButton(
                ...,
            ));
      

但是我得到了这个错误:

我不知道为什么会这样。

我最终给了 Scaffold 一个密钥并使用了 GlobalKey&lt;ScaffoldState&gt; 方法,但我真的很想了解为什么在没有回调的情况下使用 ScaffoldMessenger.of(context).showSnackBar()\onPressed 不起作用

【问题讨论】:

【参考方案1】:

虽然ScaffoldMessenger.of(context) 我们需要一些时间来正确渲染(对于完整的 Scaffold)。我们可以从addPostFrameCallback 知道时间。此外,如果您尝试显示小部件的中间部分,第一部分将呈现,但其余小部件将面临此问题。

这里是build 方法的解决方案。

  WidgetsBinding.instance!.addPostFrameCallback((timeStamp) 
      _showToast(context);
    );

要正确理解这个概念,我们可以这样做。

Scaffold(
      body: Container(
        height: 100,
        color: Colors.cyanAccent,
        child: Column(
          children: [
            Text("This text will render "),
            Builder(builder: (context) 
              _showToast(context);

              ///but you will be able to see Message
              return Text("it will cause error");
            ),
            Text("This text will not render "),
          ],
        ),
      ),
    );

【讨论】:

我接受了这个答案,因为它解释了完整的脚手架渲染概念并给出了这个概念的示例。【参考方案2】:

尝试在 Future.deleayd

中添加或声明您的小吃吧
Future.delayed(Duration.zero, () async 
                  yourSnackBarFunction();
                );

【讨论】:

我的目标是了解我收到错误的原因。虽然我认为你的解决方案会奏效...... 我不推荐它,它以某种方式“欺骗”了框架,通常不可取。 我用 GlobalKey 解决了这个问题(正如我在帖子中提到的),但我真的很想了解它为什么会发生 将“构建”方法视为 Flutter 引擎的秘诀,如果发生任何需要重建的情况,如何组装您的小部件。见api.flutter.dev/flutter/material/ScaffoldState/build.html @vigdora 我认为 future.deleyed 在延迟后运行它的计算。 [computation] 将在给定的 [duration] 过去后执行,future 以计算结果完成。【参考方案3】:

在 Flutter 中,每当需要重建小部件时,框架本身都会调用 build 函数。它可以发生多次!

另一方面,当您想通知用户某事时,您通常希望显示一个 toast/snackbar。所以你可以在 onPressed 和许多其他地方显示一个snackbar,但是构建函数本身只是用于构建一个小部件,而不是直接响应用户操作。

【讨论】:

谢谢,但是当颤振绑定你使用scaffoldMessenger的上下文时,它限制你只能在无状态小部件的构建方法中使用它......我可能想在构建函数之外使用toast .. 我可能错了,但我认为您也可以从其他地方访问上下文,而不仅仅是构建方法。例如,如果您在“class _SomeState extends State”中声明一个方法,则该方法中有上下文。试一试,如果我误导了,我很抱歉,但我记得是这样使用的。 api.flutter.dev/flutter/widgets/State/context.html 检查上面的链接,在我看来,有一个名为“context”的吸气剂,您可以从 State 对象中访问它。构建函数接收 this 作为同名的函数参数有点令人困惑。 我会检查以上内容,但我认为您的想法与有状态小部件有关,而且我的问题更多是关于无状态的,我开始觉得关键方法 (GlobalKey) 是正确的,因为它可以让我更灵活

以上是关于ScaffoldMessenger.of(context).showSnackBar() 在小部件构建函数中直接调用时不起作用的主要内容,如果未能解决你的问题,请参考以下文章

红移中的 PERCENTILE_CONT()

更新声明以增加列值

Percentile_Cont 函数抛出错误

BigQuery:标准 SQL 和 PERCENTILE_CONT() 函数

如何在 Postgres 中使用带有多个分位数的 percentile_conts

SQL-对同一字段的不同内容项进行统计