Flutter | 超实用简单菜单弹出框 PopupMenuButton

7,798 阅读2分钟

相信在实际开发过程当中,肯定少不了这样的功能:

点击 AppBar 右上角的按钮,弹出一个菜单供用户选择。

幸运的是,Flutter 提供给我们了一个 Widget,直接就能实现如上的效果。

PopupMenuButton

还是老规矩,先看官方的说明:

Displays a menu when pressed and calls onSelected when the menu is dismissed because an item was selected. The value passed to onSelected is the value of the selected menu item.

One of child or icon may be provided, but not both. If icon is provided, then PopupMenuButton behaves like an IconButton.

If both are null, then a standard overflow icon is created (depending on the platform).

大致意思为:

当按下的时候显示一个菜单,选择了一个项目的时候会回调 onSelected,传递的值是所选菜单的值。

可以提供 child or icon ,但是不能同时提供。

如果为空,则提供一个默认的图标,取决于平台。

构造函数

看完了官方说明,再来看构造函数:

const PopupMenuButton({
  Key key,
  @required this.itemBuilder,
  this.initialValue,
  this.onSelected,
  this.onCanceled,
  this.tooltip,
  this.elevation = 8.0,
  this.padding = const EdgeInsets.all(8.0),
  this.child,
  this.icon,
  this.offset = Offset.zero,
  this.enabled = true,
}) : assert(itemBuilder != null),
assert(offset != null),
assert(enabled != null),
assert(!(child != null && icon != null)), // fails if passed both parameters
super(key: key);

这里面每一个参数应该都很好理解,就不做过多的解释了,

唯一必传的参数就是 itemBuilder,也可以看到后面的断言:

assert(!(child != null && icon != null)) 判断了 child 、icon 是否同时不为空,如果是的话就报错了。

简单 Demo

构造函数理解了,官方也提供了一个 Demo,我们来看一下运行效果:

再来看一下代码:

/// 首先定义了一个枚举
enum WhyFarther {
  harder,
  smarter,
  selfStarter,
  tradingCharter,
}

/// ------------------------------------

/// build 方法
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('PopupMenuButtonPage'),
      actions: <Widget>[
        PopupMenuButton<WhyFarther>(
          onSelected: (WhyFarther result) {
            setState(() {
              _selection = result;
            });
          },
          icon: Icon(Icons.more_vert),
          itemBuilder: (BuildContext context) => <PopupMenuEntry<WhyFarther>>[
            const PopupMenuItem<WhyFarther>(
              value: WhyFarther.harder,
              child: Text('Working a lot harder'),
            ),
            const PopupMenuItem<WhyFarther>(
              value: WhyFarther.smarter,
              child: Text('Being a lot smarter'),
            ),
            const PopupMenuItem<WhyFarther>(
              value: WhyFarther.selfStarter,
              child: Text('Being a self-starter'),
            ),
            const PopupMenuItem<WhyFarther>(
              value: WhyFarther.tradingCharter,
              child: Text('Placed in charge of trading charter'),
            ),
          ],
        ),
      ],
    ),
    body: Container(),
  );
}

解释一下逻辑:

  1. 首先定义了一个枚举
  2. 然后在 AppBar 的「actions」里定义了 PopupMenuButton
  3. 设置 icon 为 Icon(Icons.more_vert)
  4. itemBuilder 需返回一个 List<PopupMenuEntry<T>>
  5. 这里传入的值就是 PopupMenuItem<WhyFarther>
  6. 然后定义 onSelected 参数接收点击回调

这样整体的逻辑就是定义好了,运行一下:

总结

这样就完成了一个超级简单并且实用的菜单弹出框,

其实它的实现逻辑和 DropdownButton 差不多,都是使用了 PopupRoute

有对这方面感兴趣的同学,可以查看我以前写的文章:Flutter 源码系列:DropdownButton 源码浅析

完整代码已经传至GitHub:github.com/wanglu1209/…

img