toly-popover-usage
TolyPopover 浮层组件使用规范。在需要实现弹出浮层(表情面板、右键菜单、@选择器等)时激活,确保使用正确的 API 和配置方式。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
TolyPopover 浮层组件使用规范。在需要实现弹出浮层(表情面板、右键菜单、@选择器等)时激活,确保使用正确的 API 和配置方式。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
GitHub Release 发布操作规范。在需要发布版本、上传安装包到 GitHub Release 时激活,确保使用正确的命令和流程。
确认/删除等交互弹框统一使用 showTolyPopPicker 底部弹出样式。在需要弹出确认框、删除确认、操作选择时激活,确保交互风格一致。
后端服务启动与数据库操作规范。在需要启动后端服务、运行 API 测试、执行数据库迁移或遇到连接错误时激活,确保使用正确的命令和流程。
功能归档规范。在归档功能版本、更新功能网、创建存档快照时激活,确保节点编号正确、网络图完整。
使用 tolyui_mediax 实现媒体预览。适用于图片九宫格展示、全屏预览、手势缩放、视频播放、Hero 动画等场景。
Flutter Widget/Page 组件代码评审技能。在需要审查组件代码质量、发现设计问题时激活,确保输出结构化的问题清单和改进建议。
| name | toly-popover-usage |
| description | TolyPopover 浮层组件使用规范。在需要实现弹出浮层(表情面板、右键菜单、@选择器等)时激活,确保使用正确的 API 和配置方式。 |
| metadata | {"model":"manual","last_modified":"Mon, 08 Jun 2026 00:00:00 GMT"} |
当需要在某个触发元素附近弹出浮层内容时使用,例如:
包名:tolyui_feedback(通过 package:tolyui_feedback/tolyui_feedback.dart 导入)
包裹触发元素的 Widget,内部管理浮层的显隐和定位。
TolyPopover(
// 浮层方位(相对于触发元素)
placement: Placement.top,
// 浮层内容(静态)
overlay: EmojiPanel(onEmojiSelected: _onSelect),
// 或:浮层内容(动态,可获取 controller)
overlayBuilder: (context, ctrl) => MyContent(onClose: ctrl.close),
// 控制器(可选,不传则内部自动创建)
controller: _popCtrl,
// 触发元素构建器(可获取 controller 来手动控制开关)
builder: (context, ctrl, child) => GestureDetector(
onTap: ctrl.open,
child: child,
),
// 子组件(builder 中的 child 参数)
child: Icon(Icons.emoji_emotions_outlined),
// 点击外部是否关闭(默认 true)
barrierDismissible: true,
// 浮层最大宽高
maxWidth: 360,
maxHeight: 300,
// 装饰配置(气泡尖角 or 普通卡片)
decorationConfig: DecorationConfig(
backgroundColor: Colors.white,
radius: Radius.circular(12),
),
// 生命周期回调
onOpen: () => debugPrint('opened'),
onClose: () => debugPrint('closed'),
)
手动控制浮层开关:
final PopoverController _ctrl = PopoverController();
// 打开浮层
_ctrl.open();
// 关闭浮层
_ctrl.close();
// 查询状态
_ctrl.isOpen;
// 通过右键位置打开(用于右键菜单)
_ctrl.open(position: details.localPosition);
浮层相对于触发元素的方位:
| 值 | 说明 |
|---|---|
Placement.top | 上方居中 |
Placement.topStart | 上方左对齐 |
Placement.topEnd | 上方右对齐 |
Placement.bottom | 下方居中 |
Placement.bottomStart | 下方左对齐 |
Placement.bottomEnd | 下方右对齐 |
Placement.left | 左侧居中 |
Placement.right | 右侧居中 |
浮层外观装饰:
// 普通卡片(圆角 + 阴影,无箭头)
DecorationConfig(
backgroundColor: Colors.white,
radius: Radius.circular(12),
isBubble: false, // 默认 true,不设会带气泡尖角!
)
// 带气泡尖角(默认行为)
DecorationConfig(
backgroundColor: Colors.white,
radius: Radius.circular(8),
// isBubble: true(默认)
bubbleMeta: BubbleMeta(spineHeight: 8, angle: 70),
)
TolyPopover(
placement: Placement.topStart,
maxWidth: 400,
maxHeight: 280,
overlay: EmojiPanel(onEmojiSelected: _onEmojiSelected),
builder: (context, ctrl, child) => GestureDetector(
onTap: () => ctrl.isOpen ? ctrl.close() : ctrl.open(),
child: child,
),
child: const Icon(Icons.emoji_emotions_outlined, size: 22),
)
final PopoverController _menuCtrl = PopoverController();
TolyPopover(
controller: _menuCtrl,
placement: Placement.bottomStart,
overlayBuilder: (context, ctrl) => _buildContextMenu(ctrl),
builder: (context, ctrl, child) => GestureDetector(
onSecondaryTapUp: (details) {
ctrl.open(position: details.localPosition);
},
child: child,
),
child: MessageBubbleContent(...),
)
final PopoverController _mentionCtrl = PopoverController();
TolyPopover(
controller: _mentionCtrl,
placement: Placement.topStart,
maxHeight: 200,
overlay: MentionPicker(
members: _members,
onSelect: (userId, nickname) {
_onMentionSelected(userId, nickname);
_mentionCtrl.close();
},
onDismiss: _mentionCtrl.close,
),
child: TextField(
controller: _textController,
onChanged: (text) {
if (_shouldShowMention(text)) {
_mentionCtrl.open();
}
},
),
)
不要用 OverlayEntry:TolyPopover 内部基于 OverlayPortal(Flutter 3.x 原生),自动管理浮层生命周期,不需要手动管理 OverlayEntry。
barrierDismissible:默认 true,点击外部自动关闭。如果浮层内有输入框(如搜索),注意 TapRegion 的分组不要冲突。
滚动自动关闭:TolyPopover 内置了 PopHideMixin,当页面滚动时会自动关闭浮层。
动画:内置淡入淡出动画(默认 250ms),通过 animDuration 和 reverseDuration 可调。
position 参数:ctrl.open(position: offset) 传入的是相对于触发元素的局部坐标,用于右键菜单场景定位。
maxWidth/maxHeight:约束浮层最大尺寸,超出时内容区域可滚动。
gap:浮层与触发元素的间距,默认根据是否有气泡尖角自动计算(有尖角时为 spineHeight + 2,无尖角时为 12)。