注意:查看本文章前請先查看更新日志,以至於該文章適合插件的最新版本
更新日志
| 詳情 | 日期 |
|---|---|
| 添加了contextual_menu插件的用法 | 2022-05-09 |
| 添加了desktop_context_menu插件的用法 | 2022-05-07 |
關於上下文菜單的插件還有一個 native_context_menu_ng ,支持所有電腦端的系統。對於該插件的用法暫時沒有時間學習和編寫,有需要的自己去插件主頁查看,有中文文檔。
context_menus
安裝🛠
點擊context_menus獲取最新版本。以下是在編寫本文章時的最新版本:
context_menus: ^1.0.1
使用🥣
要想在全局使用,就得包裹住MaterialApp:
return ContextMenuOverlay(
child: MaterialApp(...)
);
局部使用包裹住相應的組件即可。
ContextMenuOverlay
Key? key:傳入一個唯一的鍵required Widget child:子組件Widget Function(BuildContext, List )? cardBuilder:自定義上下文菜單樣式Widget Function(BuildContext, ContextMenuButtonConfig, [ContextMenuButtonStyle?])? buttonBuilder:自定義上下文菜單按鈕Widget Function(BuildContext)? dividerBuilder:上下文菜單間的間隔ContextMenuButtonStyle? buttonStyle:設置上下文菜單按鈕的樣式
ContextMenuOverlay(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 800,
maxHeight: 450,
),
child: Image.network(_image),
),
),
);
這個時候我們只能看到我們設置的圖片,點擊鼠標右鍵是沒反應的

接下來我們來為圖片添加右鍵點擊彈出上下文菜單選項,我們需要用ContextMenuRegion包裹住我們需要彈出右鍵菜單的對象:
ContextMenuOverlay(
child: ContextMenuRegion(
contextMenu: LinkContextMenu(url: src),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 800,
maxHeight: 450,
),
child: Image.network(src),
),
),
),
我們來看一下ContextMenuRegion的屬性:
Key? key:🤫required Widget child:傳遞一個子組件required Widget contextMenu:設置右鍵菜單bool isEnabled = true:是否啟用彈出菜單bool enableLongPress = true:是否啟動觸屏設備長按彈出菜單
在這里我使用了一個預設的LinkContextMenu,這個主要針對鏈接,里面已經設置了菜單項和方法:

第一個選項在瀏覽器打開可以自己試一下。
我們再來定義一個文本內容:
ContextMenuRegion(
contextMenu: TextContextMenu(data: _title),
child: Text(_title, style: const TextStyle(fontSize: 24)),
),

右鍵菜單都是英語,我想要換成中文怎么辦?那我們就自定義屬於我們自己的菜單選項就行。
自定義菜單需要用到GenericContextMenu對象,它有以下幾個屬性:
Key? key:🤫required List buttonConfigs:配置菜單選項bool injectDividers = false:將分隔線交錯到菜單中,使用 null 作為標記來指示某個位置的分隔線bool autoClose = true:點擊選項后是否自動關閉
ContextMenuRegion(
contextMenu: GenericContextMenu(
buttonConfigs: List.generate(
_songs.length,
(index) => ContextMenuButtonConfig(
_songs[index],
onPressed: () =>
BotToast.showText(text: '播放${_songs[index]}'),
),
).toList(),
),
child: const Text('歌曲列表'),

ContextMenuButtonConfig對象有5個屬性:
String label:設置顯示的標簽required void Function()? onPressed:設置點擊后調用的方法String? shortcutLabe:快捷鍵標簽Widget? icon:圖標Widget? iconHover:鼠標放上標簽后的圖標
ContextMenuButtonConfig(
_songs[index],
onPressed: () =>
BotToast.showText(text: '播放${_songs[index]}'),
shortcutLabel: 'ctrl+F${index + 1}',
icon: const Icon(Icons.album, size: 18), // 設置成18圖標就會居中和文字對齊
iconHover: const Icon(Icons.play_circle_fill_rounded, size: 18),
),

目前我們只使用了ContextMenuOverlay的child屬性,我們接下來啦看看其他的:
ContextMenuOverlay(
cardBuilder: (_, children) => Container(
color: Colors.lightBlueAccent,
child: Column(children: children),
),
child:...
),

buttonBuilder: (_, config, [__]) => TextButton(
onPressed: config.onPressed,
child: Text(
'${config.label} - 銀臨',
style: const TextStyle(color: Colors.white),
),
),

dividerBuilder: (context) => Container(height: 2, width: double.maxFinite, color: Colors.blue)
設置了毫無反應...😑
contextmenu
安裝🛠
點擊contextmenu獲取最新版本。以下是在編寫本文章時的最新版本:
contextmenu: ^3.0.0
使用🥣
將需要使用上下文菜單的組件用ContextMenuArea包裹起來,該組件有5個屬性:
Key? key:🤫required Widget child:需要上下文菜單的子元素required List Function(BuildContext) builder:上下文菜單選項double verticalPadding = 8:上下文菜單的垂直內邊距double width = 320:上下文菜單的寬
child: ContextMenuArea(
builder: (context) => List.generate(
_friends.length,
(index) => ListTile(
title: Text('給${_friends[index]}打電話'),
onTap: () => BotToast.showText(text: '正在聯系${_friends[index]}'),
),
).toList(),
child: Image.asset('assets/images/pdx.jpg'),
),

該插件還有一個showContextMenu方法,可以用來設置在其他點擊事件里面。
native_context_menu
該插件在pub.dev中標記為[UNIDENTIFIED],暫不建議使用
安裝🛠
點擊native_context_menu獲取最新版本。以下是在編寫本文章時的最新版本:
native_context_menu: ^0.2.1+4
使用🥣
需要上下文菜單的組件必須使用ContextMenuRegion包裹起來,該組件有以下幾個屬性:
Key? key:🤫required Widget child:需要上下文菜單的子元素required List menuItems:上下文菜單選項void Function(MenuItem)? onItemSelected:選中菜單的事件void Function()? onDismissed:打開上下文菜單沒有選擇時觸發Offset menuOffset = Offset.zero:菜單的位置
child: ContextMenuRegion(
menuItems: [
MenuItem(title: '全選'),
MenuItem(title: '復制'),
MenuItem(title: '剪切'),
MenuItem(title: '粘貼'),
MenuItem(
title: '舉報',
items: [
MenuItem(title: '發郵箱'),
MenuItem(title: '打電話'),
],
),
],
child: Text(_text, style: const TextStyle(height: 1.5)),
),

為選項添加事件:
child: ContextMenuRegion(
onItemSelected: (item) => BotToast.showText(text: '你選中了$item'),
menuItems: ...,
child: ...,
),

我們可以發現,最終點擊獲得的是一個MenuItem對象,它有以下幾個屬性:
required String title:選項的標簽void Function()? onSelected:被選中的事件Object? action:不知道傳入有啥用😪List items = const []:子選項
所以我們可以通過item.title來獲取具體選中的對象,也可以直接把方法直接寫在MenuItem上:
child: ContextMenuRegion(
...
menuItems: [
...
MenuItem(title: '復制', onSelected: () => BotToast.showText(text: '復制成功')),
...
],
...
),

呃...😥什么都沒發生,以后還是使用ContextMenuRegion的onItemSelected方法吧。
最后添加一個沒有選中選項情況下的事件:
child: ContextMenuRegion(
onDismissed: () => BotToast.showText(text: '你沒有選擇任何選項'),
onItemSelected: (item) => BotToast.showText(text: '你選中了${item.title}'),
menuItems: ...,
child: ...,
),

desktop_context_menu
安裝🛠
點擊desktop_context_menu獲取最新版本。以下是在編寫本文章時的最新版本:
desktop_context_menu: ^0.1.1
使用🥣
這個插件並沒有一個組件用來包裹需要調用右鍵菜單的內容,所以需要我們自己監聽鼠標右鍵事件。
我們需要判斷用戶按下的是鼠標右鍵
bool _openContext = false;
Listener(
onPointerDown: (e) {
_openContext = e.kind == PointerDeviceKind.mouse &&
e.buttons == kSecondaryMouseButton;
setState(() {});
},
onPointerUp: (e) {
if (_openContext) {
_showContext();
_openContext = false;
}
},
),
顯示右鍵菜單的內容就是_showContext方法,我們必須調用該插件的showContextMenu方法
_showContext() async {
await showContextMenu(
menuItems: []
);
}
該方法里需要傳入一個數組用來顯示上下文菜單中的內容。分別可以傳入ContextMenuItem和ContextMenuSeparator。
ContextMenuSeparator就是一條菜單的分割線,這里不多贅述。我們來看看ContextMenuItem。
ContextMenuItem有3個參數:
String? title:顯示的標題void Function()? onTap:點擊事件SingleActivator? shortcut:快捷鍵
_showContext() async {
await showContextMenu(
menuItems: [
ContextMenuItem(
title: '新建',
onTap: () {},
shortcut: SingleActivator(
LogicalKeyboardKey.keyN,
meta: Platform.isMacOS,
control: Platform.isWindows,
),
),
const ContextMenuSeparator(),
ContextMenuItem(
title: '剪切',
onTap: () {
BotToast.showText(text: '你按了剪切');
},
shortcut: SingleActivator(
LogicalKeyboardKey.keyV,
meta: Platform.isMacOS,
control: Platform.isWindows,
),
),
ContextMenuItem(
title: '復制',
onTap: () {
BotToast.showText(text: '你按了復制');
},
shortcut: SingleActivator(
LogicalKeyboardKey.keyC,
meta: Platform.isMacOS,
control: Platform.isWindows,
),
),
ContextMenuItem(
title: '粘貼',
onTap: () {
BotToast.showText(text: '你按了粘貼');
},
shortcut: SingleActivator(
LogicalKeyboardKey.keyV,
meta: Platform.isMacOS,
control: Platform.isWindows,
),
),
],
);
}

點擊右鍵是可以顯示菜單了,但是點擊事件好像並沒有效果。要想調用此方法需要進行以下操作
_showContext() async {
final _menu = await showContextMenu(
menuItems: [...]
);
}
然后使用以下方法
_menu.onTap?.call();

或者以下方法
if (_menu == null) return;
BotToast.showText(text: _menu!.title ?? '');

注意:該插件中的快捷鍵只能用來顯示,並不能調用方法。
contextual_menu
安裝🛠
點擊contextual_menu獲取最新版本。以下是在編寫本文章時的最新版本:
contextual_menu: ^0.1.4
使用🥣
該插件和desktop_context_menu一樣,需要自己監聽右鍵事件。這里就不多贅述。
在程序中調出上下文菜單需要使用popUpContextualMenu方法,該方法可以傳遞3個參數
Menu menu:要顯示的上下文菜單對象Offset? position:上下文菜單對象顯示的偏移量Placement placement:上下文菜單顯示的位置。默認值為Placement.bottomRight
Menu對象需要傳入一個MenuItem數組,MenuItem有以下幾種樣式:
MenuItem:普通的菜單項MenuItem.checkbox:復選框菜單項MenuItem.separator:分隔符菜單項MenuItem.submenu:子菜單項
MenuItem
有以下多個屬性:
String? key:組件唯一標識String type:菜單項的類型,主要有normal、checkbox、separator、submenu幾個值。默認為normalString? label:菜單項顯示的文本String? sublabel:菜單項顯示的二級文本String? toolTip:菜單項的提示String? icon:菜單項的圖標(猜測,目前該插件版本還有待更新,文檔並沒有對該值進行描述)bool? checked:是否被選擇。僅在type為checkbox時生效bool disabled = false:是否禁用選項。默認為falseMenu? submenu:子菜單項void Function(MenuItem)? onClick:菜單項被點擊后的方法
_showContext() {
Menu _menu = Menu(
items: [
MenuItem(label: '風起隴西'),
MenuItem.separator(),
MenuItem.submenu(
label: '9號秘事 第七季',
sublabel: '第七季',
submenu: Menu(
items: [
MenuItem.checkbox(
label: '9號秘事 第一季',
checked: false,
onClick: (menuItem) {
BotToast.showText(text: '即將播放《9號秘事 第一季》');
},
),
MenuItem.checkbox(label: '9號秘事 第二季', checked: false),
MenuItem.checkbox(label: '9號秘事 第三季', checked: false),
MenuItem.checkbox(label: '9號秘事 第四季', checked: false),
MenuItem.checkbox(label: '9號秘事 第五季', checked: false),
MenuItem.checkbox(label: '9號秘事 第六季', checked: false),
MenuItem.checkbox(label: '9號秘事 第七季', checked: true),
],
),
),
],
);
popUpContextualMenu(_menu);
}

popUpContextualMenu有一個設置偏移量的屬性,我們看看它是以哪里為標准的
popUpContextualMenu(
_menu,
position: Offset.zero,
);

popUpContextualMenu還可以通過placement屬性來設置菜單的顯示位置,如果有設置position,則該屬性以position所在位置為標准
popUpContextualMenu(
_menu,
position: Offset.zero,
placement: Placement.topLeft,
);

雖然MenuItem還有其他屬性,但是設置了並沒有效果,也許還沒完成。
🛫OK,以上就是這篇文章的全部內容,僅針對插件的當前版本,並不能保證適用於以后插件用法的更新迭代。
最后,感謝TheOneWithTheBraid 、gskinnerTeam、lesnitsky、lijy91、nfsxreloader對以上插件的開發和維護😁。本應用代碼已上傳至 github 和 gitee,有需要的可以下載下來查看學習。
