【问题标题】:How to open a PopupMenuButton?如何打开弹出菜单按钮?
【发布时间】:2017-09-07 00:32:54
【问题描述】:

如何从第二个小部件打开弹出菜单?

final button = new PopupMenuButton(
    itemBuilder: (_) => <PopupMenuItem<String>>[
          new PopupMenuItem<String>(
              child: const Text('Doge'), value: 'Doge'),
          new PopupMenuItem<String>(
              child: const Text('Lion'), value: 'Lion'),
        ],
    onSelected: _doSomething);

final tile = new ListTile(title: new Text('Doge or lion?'), trailing: button);

我想通过点击tile 打开button 的菜单。

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    这可行,但不优雅(并且与上面 Rainer 的解决方案具有相同的显示问题:

    class _MyHomePageState extends State<MyHomePage> {
      final GlobalKey _menuKey = GlobalKey();
    
      @override
      Widget build(BuildContext context) {
        final button = PopupMenuButton(
            key: _menuKey,
            itemBuilder: (_) => const<PopupMenuItem<String>>[
                  PopupMenuItem<String>(
                      child: Text('Doge'), value: 'Doge'),
                  PopupMenuItem<String>(
                      child: Text('Lion'), value: 'Lion'),
                ],
            onSelected: (_) {});
    
        final tile =
            ListTile(title: Text('Doge or lion?'), trailing: button, onTap: () {
              // This is a hack because _PopupMenuButtonState is private.
              dynamic state = _menuKey.currentState;
              state.showButtonMenu();
            });
        return Scaffold(
          body: Center(
            child: tile,
          ),
        );
      }
    }
    

    我怀疑您实际要求的内容类似于 https://github.com/flutter/flutter/issues/254https://github.com/flutter/flutter/issues/8277 跟踪的内容——将标签与控件关联并让标签可点击的能力——这是一个缺失的功能来自 Flutter 框架。

    【讨论】:

    • 谢谢埃里克!是的,那些 github 问题中描述的小部件正是我一直在寻找的东西。
    • 感谢我使用了这个解决方案
    【解决方案2】:

    我认为最好以这种方式进行,而不是显示 PopupMenuButton

    void _showPopupMenu() async {
      await showMenu(
        context: context,
        position: RelativeRect.fromLTRB(100, 100, 100, 100),
        items: [
          PopupMenuItem<String>(
              child: const Text('Doge'), value: 'Doge'),
          PopupMenuItem<String>(
              child: const Text('Lion'), value: 'Lion'),
        ],
        elevation: 8.0,
      );
    }
    

    有时您会希望在您按下按钮的位置显示_showPopupMenu 为此使用 GestureDetector

    final tile = new ListTile(
      title: new Text('Doge or lion?'),
      trailing: GestureDetector(
        onTapDown: (TapDownDetails details) {
          _showPopupMenu(details.globalPosition);
        },
        child: Container(child: Text("Press Me")),
      ),
    );
    

    然后 _showPopupMenu 会像

    _showPopupMenu(Offset offset) async {
        double left = offset.dx;
        double top = offset.dy;
        await showMenu(
        context: context,
        position: RelativeRect.fromLTRB(left, top, 0, 0),
        items: [
          ...,
        elevation: 8.0,
      );
    }
    

    【讨论】:

    • 如何在您的方法中使用 PopUpMenuButton 中的 onSelected 属性?例如,如果选择了值 Doge,我想导航到 Doge.dart 页面
    • 完美答案,我只需要用其他值替换 0:RelativeRect.fromLTRB(left, top, left+1, top+1),
    • 我认为这个菜单只是为了显示不执行任何操作
    • @Texv 在 PopupMenuItem 类中有一个用于单击回调的“onTap”属性。你可以用这个。
    【解决方案3】:

    我找到了您问题的解决方案。您可以为 PopupMenuButton 提供一个子级,它可以是任何 Widget,包括 ListTile(参见下面的代码)。唯一的问题是 PopupMenu 在 ListTile 的左侧打开。

    final popupMenu = new PopupMenuButton(
      child: new ListTile(
        title: new Text('Doge or lion?'),
        trailing: const Icon(Icons.more_vert),
      ),
      itemBuilder: (_) => <PopupMenuItem<String>>[
                new PopupMenuItem<String>(
                    child: new Text('Doge'), value: 'Doge'),
                new PopupMenuItem<String>(
                    child: new Text('Lion'), value: 'Lion'),
              ],
      onSelected: _doSomething,
    )
    

    【讨论】:

    • 使用 offset 属性进行不同的定位
    • 如何使用多级PopupMenuItems?
    【解决方案4】:

    截图:


    完整代码:

    class MyPage extends StatelessWidget {
      final GlobalKey<PopupMenuButtonState<int>> _key = GlobalKey();
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            actions: [
              PopupMenuButton<int>(
                key: _key,
                itemBuilder: (context) {
                  return <PopupMenuEntry<int>>[
                    PopupMenuItem(child: Text('0'), value: 0),
                    PopupMenuItem(child: Text('1'), value: 1),
                  ];
                },
              ),
            ],
          ),
          body: RaisedButton(
            onPressed: () => _key.currentState.showButtonMenu(),
            child: Text('Open/Close menu'),
          ),
        );
      }
    }
    

    【讨论】:

      【解决方案5】:

      使用popup_menu 包作为库

      在您的 pubspec.yaml 依赖项中添加 popup_menu: ^1.0.5。并导入它:

      import 'package:popup_menu/popup_menu.dart';
      

      首先,您应该在代码中的某处设置上下文。如下:

      PopupMenu.context = context;
      

      然后创建一个showPopup 小部件并传递所需的参数:

       void showPopup(Offset offset) {
          PopupMenu menu = PopupMenu(
              // backgroundColor: Colors.teal,
              // lineColor: Colors.tealAccent,
              maxColumn: 3,
              items: [
                MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')),
                MenuItem(title: 'Mail', image: Icon(Icons.mail, color: Colors.white)),
                MenuItem(title: 'Power',image: Icon(Icons.power, color: Colors.white,)),
              ],
              onClickMenu: onClickMenu,
              stateChanged: stateChanged,
              onDismiss: onDismiss);
          menu.show(rect: Rect.fromPoints(offset, offset));
        }
      
        void stateChanged(bool isShow) {
          print('menu is ${isShow ? 'showing' : 'closed'}');
        }
      
        void onClickMenu(MenuItemProvider item) {
          print('Click menu -> ${item.menuTitle}');
        }
      
        void onDismiss() {
          print('Menu is dismiss');
        }
      

      这是打开的弹出窗口

        @override
        Widget build(BuildContext context) {
      
        PopupMenu.context = context;  // This is the set context
      
          return Scaffold(
            appBar: AppBar(
              title: Text('Show Popup')),
            body: Stack(
              children: <Widget>[
                ListView.builder(
                  itemCount: list.length,
                  itemBuilder: (context, index) {
                   return MaterialButton(
                      child: GestureDetector(
                        onTapUp: (TapUpDetails details) {
                          showPopup(details.globalPosition);
                        },
                        child: ListTile(
                          leading: IconButton(
                            icon: Icon(Icons.restaurant_menu),
                          ),
                          title: Text("Select your categories"),
                          subtitle: Text("Sub Title"),
                          // onTap: showPopup,
                        ),
                      ),
      
                    );
                  },
                ),
              ],
            ),
          );
        }
      

      【讨论】:

        【解决方案6】:

        我认为没有办法实现这种行为。虽然您可以将onTap 属性附加到磁贴,但您无法从“外部”访问 MenuButton

        您可以采用的一种方法是使用ExpansionPanels,因为它们看起来像 ListTiles,并且旨在允许轻松修改和编辑。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多