如何打开PopupMenuButton?

时间:2017-04-11 14:36:00

标签: dart flutter

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

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);

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

6 个答案:

答案 0 :(得分:9)

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

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey _menuKey = new GlobalKey();

  @override
  Widget build(BuildContext context) {
    final button = new PopupMenuButton(
        key: _menuKey,
        itemBuilder: (_) => <PopupMenuItem<String>>[
              new PopupMenuItem<String>(
                  child: const Text('Doge'), value: 'Doge'),
              new PopupMenuItem<String>(
                  child: const Text('Lion'), value: 'Lion'),
            ],
        onSelected: (_) {});

    final tile =
        new ListTile(title: new Text('Doge or lion?'), trailing: button, onTap: () {
          // This is a hack because _PopupMenuButtonState is private.
          dynamic state = _menuKey.currentState;
          state.showButtonMenu();
        });
    return new Scaffold(
      body: new Center(
        child: tile,
      ),
    );
  }
}

我怀疑你实际要求的是https://github.com/flutter/flutter/issues/254https://github.com/flutter/flutter/issues/8277跟踪的内容 - 将标签与控件相关联并使标签可点击的功能 - 以及是Flutter框架中缺少的一个功能。

答案 1 :(得分:9)

我认为用这种方法比显示PopupMenuButton更好。

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 为此使用GestureDetector

_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,
  );
}

,然后_showPopupMenu将类似于

package com.google.common.util.concurrent;

import com.google.common.util.concurrent.RateLimiter.SleepingStopwatch;

public class RateLimiters {

    public static RateLimiter createCharged(double permitsPerSecond, double maxBurstSeconds) {
        SmoothRateLimiter.SmoothBursty rateLimiter = new SmoothRateLimiter.SmoothBursty(SleepingStopwatch.createFromSystemTimer(), maxBurstSeconds);
        rateLimiter.setRate(permitsPerSecond);
        rateLimiter.storedPermits = maxBurstSeconds * permitsPerSecond;
        return rateLimiter;
    }
}

答案 2 :(得分:2)

使用popup_menu软件包作为库

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

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,
                  ),
                ),

              );
            },
          ),
        ],
      ),
    );
  }

enter image description here

答案 3 :(得分:2)

截图:

enter image description here


完整代码:

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'),
      ),
    );
  }
}

答案 4 :(得分:1)

我找到了你问题的解决方案。您可以为PopupMenuButton提供一个子项,它可以是包含ListTile的任何Widget(请参阅下面的代码)。唯一的问题是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,
)

答案 5 :(得分:0)

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

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