Flutter Web:需要菜单和子菜单 [英] Flutter Web : Need menu with sub menu

查看:212
本文介绍了Flutter Web:需要菜单和子菜单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用Flutter网站通过如下图所示的子菜单构建菜单

How to build Menu with Submenu like shown below in image using Flutter web

推荐答案

截至目前,flutter还没有 NestedMenu 小部件.但是,现有的小部件可以帮助构建可具有不同子菜单的自定义菜单.在此 dartPad 中,我使用两种不同的思想创建了subMenu.

As of now flutter doesn't have a NestedMenu widget. However existing widgets can help build a custom menu which can have different submenu. Here in this dartPad I have created subMenu's using two different idea.

  1. 使用现有的PopupMenuButon小部件将其嵌套在另一个小部件中,并使用offset属性定位子菜单.
  2. 使用全局showMenu功能,该功能可以将菜单放置在屏幕上的任何位置.
  1. Using the Existing PopupMenuButon Widget nested one inside another and using the offset attribute to position the subMenu.
  2. Using the global showMenufunction which can position the menu anywhere in the screen.

您可以检查下面显示的两个实现.请注意,这两种方法都有其自身的警告.就像关闭弹出窗口并处理选择和取消一样.但是,这仅是为了证明其可能会扑朔迷离,而处理这些情况超出了此答案的范围.

You can check the two implementations shown below. Note both methods has its own caveats. Like dismissing the popups and handling selection and cancelling. However this is only to show its possible in flutter and handling those cases is out of scope for this answer.

嵌套的PopupMenuButton

enum WhyFarther { harder, smarter, selfStarter, tradingCharter }

class MainMenu extends StatefulWidget {
  MainMenu({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MainMenuState createState() => _MainMenuState();
}

class _MainMenuState extends State<MainMenu> {
  WhyFarther _selection = WhyFarther.smarter;

  @override
  Widget build(BuildContext context) {
// This menu button widget updates a _selection field (of type WhyFarther,
// not shown here).
    return Padding(
      padding: const EdgeInsets.all(2.0),
      child: PopupMenuButton<WhyFarther>(
        child: Material(
          textStyle: Theme.of(context).textTheme.subtitle1,
          elevation: 2.0,
          child: Container(
            padding: EdgeInsets.all(8),
            child: Text(widget.title),
          ),
        ),
        onSelected: (WhyFarther result) {
          setState(() {
            _selection = result;
          });
        },
        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: SubMenu('Sub Menu is too long'),
          ),
          const PopupMenuItem<WhyFarther>(
            value: WhyFarther.tradingCharter,
            child: Text('Placed in charge of trading charter'),
          ),
        ],
      ),
    );
  }
}

class SubMenu extends StatefulWidget {
  final String title;
  const SubMenu(this.title);

  @override
  _SubMenuState createState() => _SubMenuState();
}

class _SubMenuState extends State<SubMenu> {
  WhyFarther _selection = WhyFarther.smarter;

  @override
  Widget build(BuildContext context) {
//     print(rendBox.size.bottomRight);

    return PopupMenuButton<WhyFarther>(
      child: Row(
        children: <Widget>[
          Text(widget.title),
          Spacer(),
          Icon(Icons.arrow_right, size: 30.0),
        ],
      ),
      onCanceled: () {
        if (Navigator.canPop(context)) {
          Navigator.pop(context);
        }
      },
      onSelected: (WhyFarther result) {
        setState(() {
          _selection = result;
        });
      },
      // how much the submenu should offset from parent. This seems to have an upper limit.
      offset: Offset(300, 0),
      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 lot smarter'),
        ),
        const PopupMenuItem<WhyFarther>(
          value: WhyFarther.tradingCharter,
          child: Text('Placed in charge of trading charter'),
        ),
      ],
    );
  }
}

使用showMenu方法

class CustomMenu extends StatefulWidget {
  const CustomMenu({Key key, this.title, this.rootMenu=false}) : super(key: key);

  final String title;
  final bool rootMenu;

  @override
  _CustomMenuState createState() => _CustomMenuState();
}

class _CustomMenuState extends State<CustomMenu> {
  WhyFarther _selection = WhyFarther.smarter;

  @override
  Widget build(BuildContext context) {
// This menu button widget updates a _selection field (of type WhyFarther,
// not shown here).

    return Padding(
      padding: const EdgeInsets.all(2.0),
      child: GestureDetector(
        onTap: () {

          // This offset should depend on the largest text and this is tricky when
          // the menu items are changed
          Offset offset = widget.rootMenu?Offset.zero:Offset(-300,0);

          final RenderBox button = context.findRenderObject();
          final RenderBox overlay =
              Overlay.of(context).context.findRenderObject();
          final RelativeRect position = RelativeRect.fromRect(
            Rect.fromPoints(
              button.localToGlobal(Offset.zero, ancestor: overlay),
              button.localToGlobal(button.size.bottomRight(Offset.zero),
                  ancestor: overlay),
            ),
            offset & overlay.size,
          );
          showMenu(            
              context: context,
              position: position,
              items: <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: CustomMenu(title: 'Sub Menu long'),
                ),
                const PopupMenuItem<WhyFarther>(
                  value: WhyFarther.tradingCharter,
                  child: Text('Placed in charge of trading charter'),
                ),
              ]).then((selectedValue){
            // do something with the value
            if(Navigator.canPop(context)) Navigator.pop(context);
          });
        },
        child: Material(
              textStyle: Theme.of(context).textTheme.subtitle1,
              elevation: widget.rootMenu?2.0:0.0,              
              child: Padding(
                padding: widget.rootMenu? EdgeInsets.all(8.0):EdgeInsets.all(0.0),
                child: Row(
              children: <Widget>[
                Text(widget.title),
                if(!widget.rootMenu)
                  Spacer(),
                if(!widget.rootMenu)
                  Icon(Icons.arrow_right),                
              ],
            ),
              ),)

      ),
    );
  }
}

这篇关于Flutter Web:需要菜单和子菜单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆