Flutter:如何从 appbar 动作中显示快餐栏

Posted

技术标签:

【中文标题】Flutter:如何从 appbar 动作中显示快餐栏【英文标题】:Flutter: How to display a snackbar from an appbar action 【发布时间】:2019-04-30 19:21:58 【问题描述】:

在执行来自AppBar 的操作后,我试图显示SnackBarAppBar 无法从构建器构建,因此它无法访问 Scaffold 祖先。 我知道我们可以随时使用GlobalKey 对象来访问上下文,但我想知道是否有不使用GlobalKey 的解决方案。 我发现了一些 github 问题和 pull-request,但我无法从他们那里找到解决方案 => https://github.com/flutter/flutter/issues/4581 和 https://github.com/flutter/flutter/pull/9380

更多上下文: 我有一个Appbar 和一个PopupMenuButton,它们有一个项目。当用户单击此项目时,我会显示一个对话框,其中 showDialog 方法,如果用户单击“确定”,我想显示一个 SnackBar

【问题讨论】:

【参考方案1】:

您可以使用 Builder 小部件

例子:

Scaffold(
  appBar: AppBar(
    actions: <Widget>[
      Builder(
        builder: (BuildContext context) 
          return IconButton(
            icon: const Icon(Icons.message),
            onPressed: () 
              final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
              Scaffold.of(context).showSnackBar(snackBar);
            ,
          );
        ,
      ),
    ],
  )
);

【讨论】:

这就是我要找的东西【参考方案2】:

Scaffold.appBar 参数需要一个PreferredSizeWidget,所以你可以有一个Builder 像这样:

appBar: PreferredSize(
  preferredSize: Size.fromHeight(56),
  child: Builder(
    builder: (context) => AppBar(...),
  ),
),

【讨论】:

我尝试了您的解决方案,但是当我将上下文传递给构建警报的方法时,然后当我尝试显示 SnackBar 时,在此上下文中,我仍然有 Scaffold.of() called with a context that does not contain a Scaffold 错误。 这个解决方案对我有用。我的电话:操作:[ new IconButton(icon: const Icon(Icons.settings), onPressed: () =>_handleSettings(Scaffold.of(context))), ], 按原样运行,builder: (context) =&gt; AppBar(...),:确保您将 AppBar 代码写在括号内。如果您将 AppBar 提取到变量或方法中,它将停止工作。【参考方案3】:

一个选项是在对话框中使用两个上下文,并使用传递给对话框的上下文来搜索Scaffold

当你显示一个对话框时,你显示的是一个完全不同的页面/路由,它超出了调用页面的范围。所以没有脚手架。

下面是一个使用第一页范围的工作示例。 但是,问题在于 SnackBar 没有被删除。

如果您改为使用GlobalKey 来获取Scaffold,问题是一样的。

在这种情况下,我会考虑不使用 Snackbar,因为它与下面的页面相关联。它甚至被对话框阴影变灰。

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return new MaterialApp(
      home: new MyHomePage(),
    );
  


class MyHomePage extends StatelessWidget 
  _showDialog(BuildContext context1) 
    return showDialog(
        context: context1,
        builder: (BuildContext context) 
          return AlertDialog(
            content: Text("Dialog"),
            actions: <Widget>[
              new FlatButton(
                child: new Text("OK"),
                onPressed: () => Scaffold.of(context1).showSnackBar(SnackBar(
                      content: Text("Pressed"),
                    )),
              ),
            ],
          );
        );
  

  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Test"),
        actions: <Widget>[
          PopupMenuButton(
            itemBuilder: (BuildContext context) 
              return <PopupMenuEntry>[
                PopupMenuItem(
                  child: ListTile(
                    title: Text('Show dialog'),
                    onTap: () => _showDialog(context),
                  ),
                ),
              ];
            ,
          )
        ],
      ),
    );
  

【讨论】:

我为我的问题添加了更多上下文。我没有测试您的解决方案,但我想在来自 PopupMenuButton 项目的对话后显示 SnackBar 我已根据您提供的附加信息更改了答案。 我测试过了。由于一些奇怪的行为,我找不到将它与我的代码集成的方法,但它正在工作。但是有几个问题:SnackBar 没有消失,动作菜单也没有自行消失。

以上是关于Flutter:如何从 appbar 动作中显示快餐栏的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:如何仅在滚动后显示 AppBar?

如何在仍然显示Widgets的情况下将我的AppBar放在Flutter中的单独文件中?

Flutter:从 AppBar 中减去状态栏高度

如何在 AppBar 中包装子小部件以获得更大的子高度和 Flutter 中的填充

如何在 Flutter 的 AppBar 中有可点击的文本

长按动作栏的后退箭头在颤动中显示“返回”吐司,如何删除?