Flutter - 在BottomNavigationBar中显示PopupMenuButton

6

我正在尝试在导航栏项目被点击时显示一个菜单。这是我的尝试:

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
        length: 3,
        child: Scaffold(
            appBar: MyAppBar(
              title: "Home",
              context: context,
            ),
            bottomNavigationBar: BottomNavigationBar(
              items: [
                BottomNavigationBarItem(
                    icon: new Icon(Icons.home), title: Text('Home')),
                BottomNavigationBarItem(
                    icon: new Icon(Icons.book), title: Text('Second')),
                BottomNavigationBarItem(
                    icon: new PopupMenuButton(
                      icon: Icon(Icons.add),
                      itemBuilder: (_) => <PopupMenuItem<String>>[
                            new PopupMenuItem<String>(
                                child: const Text('test1'), value: 'test1'),
                            new PopupMenuItem<String>(
                                child: const Text('test2'), value: 'test2'),
                          ],
                    ),
                    title: Text('more')),
              ],
              currentIndex: 0,
            ),
            body: new Container()));
  }

我遇到了两个问题。第一个是NavigationBarItem的显示。在图标和标题之间有一个填充,我无法删除它(即使添加了padding: EdgeInsets.all(0.0))(如下图所示)。第二个问题是,我需要精确地点击图标才能出现菜单。 enter image description here enter image description here 当单击index=2的BottomNavigationBarItem时,我尝试直接调用showMenu(PopupMenuButton调用的方法)。但很难确定菜单应从哪里出现。
2个回答

16

以下是一种尝试,直接使用showMenu并调用函数buttonMenuPosition来获取菜单的位置。它相当脆弱,但您可以通过使用bar.size.center而不是bar.size.bottomRight将按钮位置更改为中间位置。借助一些数学知识和手动操纵Offset对象(如果/当您有超过3个选项时),您可以更改位置,使菜单出现在非中心或末尾的位置。

RelativeRect buttonMenuPosition(BuildContext c) {
    final RenderBox bar = c.findRenderObject();
    final RenderBox overlay = Overlay.of(c).context.findRenderObject();
    final RelativeRect position = RelativeRect.fromRect(
      Rect.fromPoints(
        bar.localToGlobal(bar.size.bottomRight(Offset.zero), ancestor: overlay),
        bar.localToGlobal(bar.size.bottomRight(Offset.zero), ancestor: overlay),
      ),
      Offset.zero & overlay.size,
    );
    return position;
  }


  @override
  Widget build(BuildContext context) {

    final key = GlobalKey<State<BottomNavigationBar>>();

    return DefaultTabController(
        length: 3,
        child: Scaffold(
            appBar: AppBar(
              title: Text("Home"),
            ),
            bottomNavigationBar: BottomNavigationBar(
              key: key,
              items: [
                const BottomNavigationBarItem(
                    icon: Icon(Icons.home), title: Text('Home')),
                const BottomNavigationBarItem(
                    icon: Icon(Icons.book), title: Text('Second')),
                const BottomNavigationBarItem(
                    icon: Icon(Icons.add), title: Text('more')),
              ],
              currentIndex: 0,
              onTap: (index) async {
                final position = buttonMenuPosition(key.currentContext);
                if (index == 2) {
                  final result = await showMenu(
                    context: context,
                    position: position,
                    items: <PopupMenuItem<String>>[
                      const PopupMenuItem<String>(
                          child: Text('test1'), value: 'test1'),
                      const PopupMenuItem<String>(
                          child: Text('test2'), value: 'test2'),
                    ],
                  );
                }
              },
            ),
            body: Container()));
  }

这个回答值得更多的赞!在官方文档中,如何定位showMenu小部件并不清晰,特别是当你需要相对于另一个小部件进行定位时。 - Vishnu Nair
我有类似的问题,你能回答吗?https://stackoverflow.com/questions/75512542/showmenu-anchor-from-bottom - abdullah_bd

5

这是我尝试的内容:

@override
  Widget build(BuildContext context) {
    return Material(
        child:  DefaultTabController(
        length: 3,
        child: Scaffold(
            appBar: AppBar(
              title: Text("Home"),
            ),
            bottomNavigationBar: BottomNavigationBar(
              items: [
                BottomNavigationBarItem(
                    icon: new Icon(Icons.home), title: Text('Home')),
                BottomNavigationBarItem(
                    icon: new Icon(Icons.book), title: Text('Second')),
                BottomNavigationBarItem(
                    icon: new Icon(Icons.add),
                    title: Text('More')),
              ],
              currentIndex: 0,
              onTap: (int index) async {
                if(index == 2){
                  await showMenu<String>(
                    context: context,
                    position: RelativeRect.fromLTRB(1000.0, 1000.0, 0.0, 0.0),
                    items: <PopupMenuItem<String>>[
                      new PopupMenuItem<String>(
                                child: const Text('test1'), value: 'test1'),
                            new PopupMenuItem<String>(
                                child: const Text('test2'), value: 'test2'),
                    ],
                    elevation: 8.0,
                  );
                }
              },
            ),
            body: new Container())));
  }

基本上,按照您所说的使用showMenu方法,除了我将RelativeRect的值设置为1000.0,这样它就会在任何设备的右下角。您可以尝试更改这些值以获得更接近图标上方的位置,但我认为这样做效果很好:

enter image description here


这是对rect值的硬编码,对于其他设备来说不是“可扩展”的,对吗? - denis631
我更喜欢使用 Size _size = MediaQuery.of(context).size; 然后将宽度设置为 _size.width,高度设置为 _size.height,应用于左侧和顶部的值。 - Nixon Kosgei

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