上下文菜单
用于在右键单击或长按时显示上下文菜单的包。
? 安装
dependencies:
context_menus: ^0.1.0
⚙ 导入
import 'package:context_menus/context_menus.dart';
?️ 用法
要开始使用,请将 `ContextMenuOverlay` 包装到您的主应用程序或最顶层的视图中。
return ContextMenuOverlay(
child: MaterialApp(...)
);
然后,您可以使用 `ContextMenuRegion` 小部件来包装那些应该触发上下文菜单的 Widget 树的部分。
return ContextMenuRegion(
enableLongPress: false,
// LinkContextMenu is an example menu, provided with this package
contextMenu: LinkContextMenu(url: 'https://flutterdart.cn'),
child: TextButton(onPressed: () {}, child: Text("https://flutterdart.cn")),
),
`ContextMenuRegion` 会监听右键单击和(可选的)长按事件。它需要一个 `contextMenu` 小部件,该小部件将在触发其中一个输入事件时显示。
虽然此包提供了一些默认菜单、按钮以及一个用于样式设置的系统,但**重要的是要注意 `contextMenu` 可以是您喜欢的任何小部件。**您可以自由地用自己的菜单内容替换所有这些,而仅依赖插件来管理定位和可见性。
? 自定义菜单
通用上下文菜单 (GenericContextMenu)
创建自定义菜单的最简单方法是使用 `GenericContextMenu`。只需向其传递 `ContextMenuButtonConfig` 列表,它将使用内置的 `ContextMenuButton` 和 `ContextMenuCard` 小部件创建菜单。
/// Custom Context Menu for an Image
ContextMenuRegion(
contextMenu: GenericContextMenu(
buttonConfigs: [
ContextMenuButtonConfig(
"View image in browser",
onPressed: () => launch(_testImageUrl),
),
ContextMenuButtonConfig(
"Copy image path",
onPressed: () => Clipboard.setData(ClipboardData(text: _testImageUrl)),
)
],
),
child: Image.network(_testImageUrl),
),
使用 `GenericContextMenu` 时,按钮的视觉样式将由 `ContextMenuOverlay.buttonStyle` 属性决定,但也可以通过 `GenericContextMenu.buttonStyle` 进行覆盖。
ContextMenuStateMixin
创建自定义菜单的另一种简单方法是创建一个 `StatefulWidget` 并使用 `ContextMenuStateMixin` 以及 `cardBuilder` 和 `buttonBuilder` 代理。
您可以在现有 `LinkContextMenu` 中看到这一点。
class _LinkContextMenuState extends State<LinkContextMenu> with ContextMenuStateMixin {
@override
Widget build(BuildContext context) {
// cardBuilder is provided to us by the mixin, we must pass it a list of children to layout
return cardBuilder.call(
context,
[
// buttonBuilder is also provided by the mixin, use it to build each btn
buttonBuilder.call(
context,
// button builder needs a config, so it knows how to setup the btn
ContextMenuButtonConfig(
"Open link in new window",
icon: widget.useIcons ? Icon(Icons.link, size: 18) : null,
onPressed: () => handlePressed(context, _handleNewWindowPressed),
),
),
buttonBuilder.call(
context,
ContextMenuButtonConfig(
"Copy link address",
icon: widget.useIcons ? Icon(Icons.copy, size: 18) : null,
onPressed: () => handlePressed(context, _handleClipboardPressed),
),
)
],
);
}
在上面的示例中,您可以直接提供自己的 Card 和 Buttons,而不是使用构建器,但构建器为您提供了几个优势:
- 您可以全局样式化所有菜单,方法是编辑 `ContextMenuOverlay` 上的构建器。
- 所有按钮都会在触发时自动关闭上下文菜单,这是标准行为。
- 您的自定义菜单将匹配此包附带的 `LinkMenu` 和 `GenericContextMenu`。
提供您自己的小部件
如果您只想使用自己的一组菜单并跳过构建器,只需直接传递即可。
ContextMenuRegion(
contextMenu: Container(width: 150, child: Column(children: [ ... ])),
child: ...,
),
请注意,如果您从头开始提供自己的菜单,您将负责设置菜单的水平约束,并在按下项目时关闭菜单。此时,插件将仅处理内容靠近鼠标的定位,并在右键单击或长按时显示内容。
✨ ️样式
您有三种修改样式的选项:
- 将 `ContextMenuButtonStyle` 传递给 `ContextMenuOverlay` 进行小的样式调整。
- 使用您自己的 `cardBuilder` 或 `buttonBuilder` 代理以获得更多控制。
- 直接传递您自己的自定义菜单小部件以获得完全控制。
对于基本样式,只需将按钮样式值传递给 `ContextMenuOverlay`。
return ContextMenuOverlay(
buttonStyle: ContextMenuButtonStyle(
fgColor: Colors.green,
bgColor: Colors.green.shade100,
hoverFgColor: Colors.green,
hoverBgColor: Colors.green.shade200,
),
child: MaterialApp(...);
}
为了获得更多控制,您可以覆盖 `cardBuilder` 和 `buttonBuilder` 代理,并选择性地使用提供的样式值。
return ContextMenuOverlay(
/// Make a custom background
cardBuilder: (_, children) => Container(color: Colors.purple.shade100, child: Column(children: children)),
/// Make custom buttons
buttonBuilder: (_, config, [__]) => TextButton(
onPressed: config.onPressed,
child: Container(width: double.infinity, child: Text(config.label)),
),
child: MaterialApp( ... ),
);
如上所述,您始终可以直接将自定义菜单提供给 `ContextMenuRegion`,从而完全绕过提供的样式系统。
?️ 手动控制
如果您想手动显示或关闭菜单,可以查找覆盖层并直接控制它。
ContextMenuOverlay.of(context).show(Container(width: 100, height: 100, color: Colors.red))
...
ContextMenuOverlay.of(context).hide();
这也可以通过 `BuildContext` 上的快捷方式扩展来表达。
context.contextMenuOverlay.close();
? Bug/需求
如果您遇到任何问题,请打开一个 issue。如果您觉得库缺少某个功能,请在 Github 上提交一个 ticket,我们将进行审查。欢迎提交 Pull Request。
? 许可证
MIT 许可