Flutter3.7新增Menu菜單組件的使用教程分享
菜單組件介紹
本次Flutter
穩(wěn)定版本菜單系列組件新增了 MenuAnchor
、MenuBar
、SubmenuButton
、MenuItemButton
組件, 這四個(gè)組件可以單獨(dú)使用也可以相互配合使用。他們都位于menu_anchor.dart
文件內(nèi),下面對(duì)這幾個(gè)組件詳細(xì)介紹下。
MenuAnchor組件
這是一個(gè)具有子菜單的獨(dú)立區(qū)域組件,點(diǎn)進(jìn)去我們可以看到是一個(gè)StatefulWidget
組件, 這四個(gè)組件除了MenuBar
是靜態(tài)組件,其他都是動(dòng)態(tài)組件。
說明我們可以當(dāng)作普通的Widget
組件去使用它們,MenuAnchor
可以獨(dú)立使用,通過這一個(gè)組件可以簡(jiǎn)單的實(shí)現(xiàn)下拉菜單的功能。
構(gòu)造函數(shù):
const MenuAnchor({ super.key, this.controller,// 控制器 this.childFocusNode,//如果菜單是輸入框,焦點(diǎn)控制 this.style, //菜單樣式 this.alignmentOffset = Offset.zero,//相對(duì)于組件左下角位置 this.clipBehavior = Clip.none,// 超出屏幕剪切 不常用 this.anchorTapClosesMenu = false,// 設(shè)置為true時(shí),菜單打開時(shí),點(diǎn)擊會(huì)重復(fù)打開。 this.onOpen,//打開回調(diào) this.onClose,//關(guān)閉回調(diào) this.crossAxisUnconstrained = true, required this.menuChildren,//下拉菜單列表 this.builder,//組件本身,通常是控制菜單的按鈕 this.child,//傳遞給上方builder里的child組件 });
官方示例:
官方示例菜單后面的字母是自定義快捷鍵的操作,我們重點(diǎn)看下菜單的聯(lián)動(dòng)功能,菜單聯(lián)動(dòng)是和SubmenuButton
實(shí)現(xiàn)的,例如官方示例中的設(shè)置背景色的菜單就是使用它實(shí)現(xiàn)的。接下來介紹下這個(gè)組件。
SubmenuButton 聯(lián)級(jí)菜單按鈕
通過這個(gè)按鈕可以實(shí)現(xiàn)菜單的聯(lián)級(jí)調(diào)用,一般用來該選項(xiàng)下還有下級(jí)菜單時(shí)使用。該組件一般和MenuAnchor
和MenuBar
配合使用。
const SubmenuButton({ super.key, this.onHover,//按鈕是否選中回調(diào) 在pc端屬于鼠標(biāo)指針在此菜單上 this.onFocusChange,//是否獲取焦點(diǎn)回調(diào) this.onOpen,//打開下級(jí)菜單回調(diào) this.onClose,//關(guān)閉下級(jí)菜單回調(diào) this.style,//按鈕本身樣式 this.menuStyle,//下級(jí)菜單樣式 this.alignmentOffset,//相對(duì)位置偏移量 默認(rèn)和組件上邊對(duì)齊 this.clipBehavior = Clip.none, this.focusNode, this.statesController,//組件狀態(tài)擴(kuò)展 this.leadingIcon,//左邊可選圖標(biāo) this.trailingIcon,//右邊可選圖標(biāo) required this.menuChildren,//聯(lián)級(jí)菜單 required this.child,//組件本身 });
MenuItemButton 菜單按鈕組件
具體菜單的選項(xiàng),一般菜單選項(xiàng)沒有下一級(jí)菜單時(shí)具有具體的功能使用,通過構(gòu)造方法可以自定義快捷鍵,快捷鍵功能一般在PC端上使用。
構(gòu)造方法:
const MenuItemButton({ super.key, this.onPressed,//點(diǎn)擊事件 this.onHover,//選中回調(diào) this.requestFocusOnHover = true,//指針懸停是否聚焦 this.onFocusChange,//是否獲取焦點(diǎn)回調(diào) this.focusNode,//焦點(diǎn)控制 this.shortcut,//快捷鍵設(shè)置 this.style,//本身樣式 this.statesController,//組件狀態(tài)擴(kuò)展 this.clipBehavior = Clip.none, this.leadingIcon,//... this.trailingIcon,//... required this.child,//... });
MenuBar 多菜單聯(lián)級(jí)菜單頭部Bar
此組件是管理多個(gè)聯(lián)級(jí)菜單頭部的組件,例如掘金編輯器下圖,如果菜單選項(xiàng)只有1個(gè)可以使用MenuAnchor
,多個(gè)時(shí)使用MenuBar
.
紅框內(nèi)的組件集就是MenuBar
組件的作用,它可以管理各個(gè)菜單之間的聯(lián)動(dòng),默認(rèn)他們共用一個(gè)控制器。一般和SubmenuButton
、MenuItemButton
配合使用。
const MenuBar({ super.key, this.style,// 菜單樣式 this.clipBehavior = Clip.none, this.controller, required this.children, });
示例效果:
左邊的菜單1、2、3是一組MenuBar
組件,右邊是可以獨(dú)立的MenuAnchor
組件。
示例源碼:
相較于官方示例,該示例下方展示了上方四個(gè)菜單組件的單獨(dú)使用以及聯(lián)合使用的簡(jiǎn)單示例,去掉了快捷鍵設(shè)置的屬性,更直觀的了解菜單組件的使用。快捷鍵的使用一般在PC端使用。
import 'package:flutter/material.dart'; void main() => runApp(const MenuApp()); enum MenuEntry { about('About'), showMessage('Show Message'), hideMessage('Hide Message'), colorMenu('Color Menu'), colorRed('Red Background'), colorGreen('Green Background'), colorBlue('Blue Background'); final String label; const MenuEntry(this.label); } class MyCascadingMenu extends StatefulWidget { const MyCascadingMenu({super.key, required this.message}); final String message; @override State<MyCascadingMenu> createState() => _MyCascadingMenuState(); } class _MyCascadingMenuState extends State<MyCascadingMenu> { MenuEntry? _lastSelection; final FocusNode _buttonFocusNode = FocusNode(debugLabel: 'Menu Button'); Color get backgroundColor => _backgroundColor; Color _backgroundColor = Colors.red; set backgroundColor(Color value) { if (_backgroundColor != value) { setState(() { _backgroundColor = value; }); } } bool get showingMessage => _showingMessage; bool _showingMessage = false; set showingMessage(bool value) { if (_showingMessage != value) { setState(() { _showingMessage = value; }); } } @override void dispose() { _buttonFocusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ MenuBar( style: MenuStyle( backgroundColor: MaterialStateColor.resolveWith((states) => Colors.white),), children: [ SubmenuButton(menuChildren: _meunList(), child: const Text("菜單1")), SubmenuButton(menuChildren: _meunList(), child: const Text("菜單2")), SubmenuButton(menuChildren: _meunList(), child: const Text("菜單3")), MenuAnchor( childFocusNode: _buttonFocusNode, menuChildren: _meunList(), builder: (BuildContext context, MenuController controller, Widget? child) { return TextButton( focusNode: _buttonFocusNode, onPressed: () { if (controller.isOpen) { controller.close(); } else { controller.open(); } }, child: const Text('OPEN MENU'), ); }, ), ]), Expanded( child: Container( alignment: Alignment.center, color: backgroundColor, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Padding( padding: const EdgeInsets.all(12.0), child: Text( showingMessage ? widget.message : '', style: Theme.of(context).textTheme.headlineSmall, ), ), Text(_lastSelection != null ? 'Last Selected: ${_lastSelection!.label}' : ''), ], ), ), ), ], ); } void _activate(MenuEntry selection) { setState(() { _lastSelection = selection; }); switch (selection) { case MenuEntry.about: showAboutDialog( context: context, applicationName: 'MenuBar Sample', applicationVersion: '1.0.0', ); break; case MenuEntry.hideMessage: case MenuEntry.showMessage: showingMessage = !showingMessage; break; case MenuEntry.colorMenu: break; case MenuEntry.colorRed: backgroundColor = Colors.red; break; case MenuEntry.colorGreen: backgroundColor = Colors.green; break; case MenuEntry.colorBlue: backgroundColor = Colors.blue; break; } } List<Widget> _meunList() { return <Widget>[ MenuItemButton( child: Text(MenuEntry.about.label), onPressed: () => _activate(MenuEntry.about), ), if (_showingMessage) MenuItemButton( onPressed: () => _activate(MenuEntry.hideMessage), child: Text(MenuEntry.hideMessage.label), ), if (!_showingMessage) MenuItemButton( onPressed: () => _activate(MenuEntry.showMessage), child: Text(MenuEntry.showMessage.label), ), SubmenuButton( leadingIcon: const Icon(Icons.ac_unit_sharp), menuChildren: <Widget>[ MenuItemButton( onPressed: () => _activate(MenuEntry.colorRed), child: Text(MenuEntry.colorRed.label), ), MenuItemButton( onPressed: () => _activate(MenuEntry.colorGreen), child: Text(MenuEntry.colorGreen.label), ), MenuItemButton( onPressed: () => _activate(MenuEntry.colorBlue), child: Text(MenuEntry.colorBlue.label), ), ], child: const Text('Background Color'), ), ]; } } class MenuApp extends StatelessWidget { const MenuApp({super.key}); static const String kMessage = '"Talk less. Smile more." - A. Burr'; @override Widget build(BuildContext context) { return const MaterialApp( home: Scaffold(body: MyCascadingMenu(message: kMessage)), ); } }
菜單樣式 MenuStyle
構(gòu)造方法:
構(gòu)造方法內(nèi)大多數(shù)參數(shù)使用的是 MaterialStateProperty<T>
具有狀態(tài)選擇設(shè)置,這樣做的好處是在PC端例如懸停、點(diǎn)擊、不可點(diǎn)擊等狀態(tài)設(shè)置不同樣式時(shí),會(huì)非常的方便。例如系統(tǒng)自帶的顏色、邊框MaterialStateColor
、MaterialStateBorderSide
等都是通過 MaterialStateProperty
擴(kuò)展的。
const MenuStyle({ this.backgroundColor, this.shadowColor, this.surfaceTintColor, this.elevation, this.padding, this.minimumSize, this.fixedSize, this.maximumSize, this.side, this.shape, this.mouseCursor, this.visualDensity, this.alignment, });
原生系統(tǒng)菜單系列組件
使用平臺(tái)原生菜單組件實(shí)現(xiàn),非Flutter渲染,例如在MacOS系統(tǒng)上特別有用,因?yàn)樵贛acOS上需要一個(gè)系統(tǒng)級(jí)菜單。
- PlatformMenuBar
- PlatformMenu
- PlatformMenuItem
- PlatformMenuItemGroup
- ...
使用方法大同小異,區(qū)別就是這是基于不同平臺(tái)實(shí)現(xiàn)的系統(tǒng)菜單選項(xiàng)。
小結(jié)
上面就是本次更新新增的菜單相關(guān)使用的組件,可以看出這一系列組件更傾向于桌面端使用,里面加入了實(shí)現(xiàn)快捷鍵的操作,反而對(duì)于移動(dòng)端操作需要的菜單以外部分的陰影,菜單彈出動(dòng)畫都沒有找到支持的方法。
以上就是Flutter3.7新增Menu菜單組件的使用教程分享的詳細(xì)內(nèi)容,更多關(guān)于Flutter Menu菜單組件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
android輸入框與文本框加滾動(dòng)條scrollview示例
這篇文章主要介紹了android輸入框與文本框加滾動(dòng)條scrollview示例,需要的朋友可以參考下2014-05-05BootStrapValidator與My97日期校驗(yàn)的實(shí)例代碼
這篇文章給大家介紹了bootstrapvalidator與my97日期校驗(yàn)的實(shí)例代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-01-01關(guān)于androidstuio導(dǎo)入系統(tǒng)源碼的問題
小編最近在做系統(tǒng)源碼導(dǎo)出來的小項(xiàng)目,在導(dǎo)入androidstudio過程中遇到過一些問題,本文以Schedule power on off為例給大家詳細(xì)介紹,需要的朋友參考下吧2021-06-06詳解Android中OkHttp3的例子和在子線程更新UI線程的方法
本篇文章主要介紹了詳解Android中OkHttp3的例子和在子線程更新UI線程的方法 ,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-05-05Android ViewPager無限循環(huán)滑動(dòng)并可自動(dòng)滾動(dòng)完整實(shí)例
對(duì)于Android ViewPager廣告頁(yè)可無限循環(huán)滑動(dòng)并可自動(dòng)滾動(dòng)帶有小圓點(diǎn)的這個(gè)功能很多APP都有這個(gè)功能,這里為大家提供了完整的實(shí)例代碼2018-03-03Android實(shí)現(xiàn)注冊(cè)頁(yè)面(攜帶數(shù)據(jù)包跳轉(zhuǎn))
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)注冊(cè)頁(yè)面,點(diǎn)擊注冊(cè)按鈕跳轉(zhuǎn)到另一個(gè)頁(yè)面并顯示輸入信息,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04