Flutter:如何从AppBar操作显示Snackbar

10
我想在从AppBar执行一个操作后显示一个SnackBar。由于AppBar无法通过builder构建,因此无法访问其Scaffold祖先。我知道我们可以使用GlobalKey对象在需要时访问上下文,但我想知道是否有不使用GlobalKey的解决方案。我找到了一些github问题和pull-request,但是我无法从中找到解决方案=> https://github.com/flutter/flutter/issues/4581https://github.com/flutter/flutter/pull/9380 更多背景信息: 我有一个带有PopupMenuButtonAppbar,其中有一个项。当用户点击该项时,我使用showDialog方法显示对话框,如果用户点击“ok”,我想显示一个SnackBar
3个回答

14
您可以使用构建器小部件。
例如:
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);
            },
          );
        },
      ),
    ],
  )
);

这正是我所寻找的。 - vishalknishad

9

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”错误。 - Quentin
1
这个解决方案对我有用。我的调用: actions: <Widget>[ new IconButton(icon: const Icon(Icons.settings), onPressed: () =>_handleSettings(Scaffold.of(context))), ], - AlanKley
这段代码是可行的,builder: (context) => AppBar(...),:请确保您将AppBar代码写在括号里面。如果将AppBar提取到变量或方法中,它将停止工作。 - WSBT

1
一个选项是在对话框中使用两个上下文,并使用传递给对话框的上下文来搜索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 - Quentin
根据您提供的额外信息,我已经修改了我的答案。 - chemamolins
1
我测试过了。由于一些奇怪的行为,我找不到将其与我的代码集成的方法,但它是有效的。但是还有几个问题:SnackBar不会消失,操作菜单也不会自动消失。 - Quentin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接