flutter 如何打开PopupMenuButton?

gdrx4gfi  于 2022-12-05  发布在  Flutter
关注(0)|答案(7)|浏览(164)

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

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的菜单。

bxjv4tth

bxjv4tth1#

这是可行的,但不够优雅(并且具有与上面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框架中缺少的一个功能。

r7s23pms

r7s23pms2#

我认为这样做会更好,而不是显示一个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,
  );
}
slmsl1lt

slmsl1lt3#

屏幕截图:

完整代码:

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

xbp102n04#

我找到了一个解决你问题的方法。你可以为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,
)
8ljdwjyq

8ljdwjyq5#

我不认为有一种方法可以实现这种行为。虽然你可以附加一个onTap属性到图块,但你不能从“外部”访问MenuButton
您可以采用的一种方法是使用ExpansionPanels,因为它们看起来像ListTiles,旨在允许轻松修改和编辑。

yruzcnhs

yruzcnhs6#

如果你使用的是材料showMenu,但你的菜单不能正常工作或在错误的地方打开按照我的答案。
此答案基于Vishal Singh的答案。
GestureDetector中,使用onLongPressStartonTapUp向函数发送偏移量。

onLongPressStart: (detail){
   _showPopupMenu(detail.globalPosition);
},

onLongPress相当于onLongPressStart(并在其后立即呼叫)。
onTapUp,它与onTap同时调用,但包含有关指针位置的详细信息。
对于菜单位置,请执行以下操作

position: RelativeRect.fromDirectional(textDirection: Directionality.of(context), start: left, top: top, end: left+2, bottom: top+2)

全码

_showPopupMenu(Offset offset) async {
      double left = offset.dx;
      double top = offset.dy;
      await showMenu(
        context: context,
        shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.all(
                Radius.circular(AppConst.borderRadiusSmall))),
        position: RelativeRect.fromDirectional(textDirection: Directionality.of(context), start: left, top: top, end: left+2, bottom: top+2),
        items: _getMenuItems(menu),
        elevation: 8.0,
      ).then((value) {
        value?.onTap.call();
      });
    }
oyxsuwqo

oyxsuwqo7#

class MyPage extends StatefulWidget {
  @override
  State<MyPage> createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
  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'),
      ),
    );
  }
}

相关问题