# 弹出菜单(PluginPopupMenu)
PluginPopupMenu 提供弹出式菜单功能,可在指定的锚点视图附近显示菜单列表。支持菜单项图标、可选中状态、分组管理、多级子菜单等丰富功能,适用于上下文菜单、选项菜单等场景。
# 快速开始
// 创建弹出菜单
PluginPopupMenu popupMenu = pluginUI.createPopupMenu(anchorView);
// 获取菜单并添加菜单项
PluginMenu menu = popupMenu.getMenu();
menu.add("item1", "菜单项 1");
menu.add("item2", "菜单项 2");
menu.add("item3", "菜单项 3");
// 设置菜单项点击监听器
popupMenu.setOnMenuItemClickListener(item -> {
pluginUI.showToast("点击了:" + item.getTitle());
return true; // 返回 true 表示已处理该事件
});
// 显示菜单
popupMenu.show();
# 接口概览
# PluginPopupMenu 接口
| 方法 | 说明 |
|---|---|
getMenu() | 获取菜单对象 |
setGravity(int) | 设置菜单对齐方式 |
getGravity() | 获取菜单对齐方式 |
show() | 显示弹出菜单 |
dismiss() | 关闭弹出菜单 |
setOnMenuItemClickListener() | 设置菜单项点击监听器 |
setOnDismissListener() | 设置菜单关闭监听器 |
# PluginMenu 接口
| 方法 | 说明 |
|---|---|
add(CharSequence) | 添加菜单项(ID 和标题相同) |
add(String, CharSequence) | 添加菜单项(指定 ID 和标题) |
add(String, CharSequence, String) | 添加菜单项(指定 ID、标题和分组) |
addSubMenu(CharSequence) | 添加子菜单(ID 和标题相同) |
addSubMenu(String, CharSequence) | 添加子菜单(指定 ID 和标题) |
addSubMenu(String, CharSequence, String) | 添加子菜单(指定 ID、标题和分组) |
findItem(String) | 根据 ID 查找菜单项 |
getItem(int) | 获取指定索引的菜单项 |
size() | 获取菜单项总数 |
setGroupCheckable() | 设置分组的可选中状态 |
setGroupVisible() | 设置分组的可见性 |
setGroupEnabled() | 设置分组的启用状态 |
setGroupDividerEnabled() | 设置是否显示分组分隔线 |
clear() | 清空菜单 |
# PluginMenuItem 接口
| 方法 | 说明 |
|---|---|
getItemId() | 获取菜单项 ID |
getGroupId() | 获取菜单项所属分组 ID |
setTitle(CharSequence) | 设置标题 |
getTitle() | 获取标题 |
setIcon(Drawable) | 设置图标 |
getIcon() | 获取图标 |
setIconTintList(ColorStateList) | 设置图标着色 |
getIconTintList() | 获取图标着色 |
setCheckable(boolean) | 设置是否可选中 |
isCheckable() | 获取是否可选中 |
setChecked(boolean) | 设置选中状态 |
isChecked() | 获取选中状态 |
setVisible(boolean) | 设置可见性 |
isVisible() | 获取可见性 |
setEnabled(boolean) | 设置启用状态 |
isEnabled() | 获取启用状态 |
hasSubMenu() | 判断是否包含子菜单 |
getSubMenu() | 获取子菜单 |
# PluginSubMenu 接口
| 方法 | 说明 |
|---|---|
setIcon(Drawable) | 设置子菜单图标 |
getItem() | 获取代表此子菜单的菜单项 |
提示:PluginSubMenu 继承自 PluginMenu,因此也具有 PluginMenu 的所有方法。
# 创建弹出菜单
# createPopupMenu
PluginPopupMenu createPopupMenu(PluginView anchor)
通过 pluginUI.createPopupMenu(anchor) 创建弹出菜单,菜单将相对于锚点视图显示。
参数:
anchor- 锚点视图,菜单将相对于该视图显示
返回值: PluginPopupMenu 弹出菜单实例
示例:
// 在按钮点击时显示弹出菜单
button.setOnClickListener(view -> {
PluginPopupMenu popupMenu = pluginUI.createPopupMenu(view);
PluginMenu menu = popupMenu.getMenu();
menu.add("选项1");
menu.add("选项2");
popupMenu.show();
});
# 菜单管理
# 添加菜单项
PluginMenu 提供三种重载形式的 add() 方法:
# add(CharSequence idAndTitle)
PluginMenuItem add(CharSequence idAndTitle)
添加菜单项,使用相同的值作为 ID 和标题。
参数:
idAndTitle- 同时作为 ID 和标题的文本
示例:
menu.add("菜单项1"); // ID 和标题都是 "菜单项1"
menu.add("{menu2}"); // ID 是 "{menu2}",标题会转为本地化文本
注意:如果
idAndTitle是{key}格式,ID 仍然是{key}(不会转换),但标题会自动转换为本地化文本。
# add(String id, CharSequence title)
PluginMenuItem add(String id, CharSequence title)
添加菜单项,分别指定 ID 和标题。
参数:
id- 菜单项的唯一标识符title- 菜单项的标题,支持{key}格式的本地化文本
示例:
menu.add("item1", "菜单项 1");
menu.add("item2", "{menu_title}"); // 标题使用本地化文本
# add(String id, CharSequence title, String groupId)
PluginMenuItem add(String id, CharSequence title, String groupId)
添加菜单项,指定 ID、标题和分组。
参数:
id- 菜单项的唯一标识符title- 菜单项的标题,支持{key}格式的本地化文本groupId- 菜单项所属的分组 ID,null 表示不分组
示例:
// 添加到同一分组
menu.add("option1", "选项1", "group1");
menu.add("option2", "选项2", "group1");
menu.add("option3", "选项3", "group1");
# 添加子菜单
PluginMenu 提供三种重载形式的 addSubMenu() 方法,用法与 add() 类似:
PluginSubMenu addSubMenu(CharSequence idAndTitle)
PluginSubMenu addSubMenu(String id, CharSequence title)
PluginSubMenu addSubMenu(String id, CharSequence title, String groupId)
示例:
// 创建子菜单
PluginSubMenu subMenu = menu.addSubMenu("sub1", "子菜单1");
subMenu.add("item1", "子项1");
subMenu.add("item2", "子项2");
subMenu.add("item3", "子项3");
// 为子菜单设置图标
subMenu.setIcon(MaterialIcons.get("folder"));
# 查找菜单项
# findItem
PluginMenuItem findItem(String id)
根据 ID 查找菜单项。
参数:
id- 菜单项 ID
返回值: 对应的菜单项,如果未找到则返回 null
示例:
PluginMenuItem item = menu.findItem("item1");
if (item != null) {
item.setEnabled(false); // 禁用该菜单项
}
# getItem
PluginMenuItem getItem(int index)
获取指定索引位置的菜单项。
参数:
index- 菜单项索引(从 0 开始)
返回值: 对应索引的菜单项
# size
int size()
获取菜单项总数。
返回值: 菜单中的项目数量
# 清空菜单
void clear()
清空菜单中的所有项目。
示例:
// 动态更新菜单
menu.clear();
menu.add("新选项1");
menu.add("新选项2");
# 菜单项配置
# 标题和图标
# setTitle
PluginMenuItem setTitle(CharSequence title)
设置菜单项的标题。
参数:
title- 菜单项标题,支持{key}格式的本地化文本
返回值: 当前菜单项实例,支持链式调用
示例:
menu.add("item1", "原标题")
.setTitle("新标题");
# setIcon
PluginMenuItem setIcon(Drawable icon)
设置菜单项图标。
参数:
icon- 图标 Drawable,null 表示移除图标
返回值: 当前菜单项实例,支持链式调用
示例:
menu.add("search", "搜索")
.setIcon(MaterialIcons.get("search"));
menu.add("copy", "复制")
.setIcon(MaterialIcons.get("content_copy"));
# setIconTintList
PluginMenuItem setIconTintList(ColorStateList tint)
设置图标的着色列表。
参数:
tint- 颜色状态列表,null 表示移除着色
返回值: 当前菜单项实例,支持链式调用
# 可选中状态
# setCheckable
PluginMenuItem setCheckable(boolean checkable)
设置菜单项是否可选中。
参数:
checkable- 是否可选中
返回值: 当前菜单项实例,支持链式调用
# setChecked
PluginMenuItem setChecked(boolean checked)
设置菜单项的选中状态。
参数:
checked- 是否选中
返回值: 当前菜单项实例,支持链式调用
示例:
menu.add("option1", "选项1")
.setCheckable(true)
.setChecked(true); // 默认选中
# 可见性和启用状态
# setVisible
PluginMenuItem setVisible(boolean visible)
设置菜单项的可见性。
参数:
visible- 是否可见
返回值: 当前菜单项实例,支持链式调用
# setEnabled
PluginMenuItem setEnabled(boolean enabled)
设置菜单项的启用状态。
参数:
enabled- 是否启用
返回值: 当前菜单项实例,支持链式调用
示例:
menu.add("disabled", "禁用选项")
.setEnabled(false); // 禁用该菜单项
menu.add("hidden", "隐藏选项")
.setVisible(false); // 隐藏该菜单项
# 子菜单
# hasSubMenu
boolean hasSubMenu()
判断菜单项是否包含子菜单。
返回值: true 表示包含子菜单,false 表示不包含
# getSubMenu
PluginSubMenu getSubMenu()
获取菜单项的子菜单。
返回值: 子菜单对象,如果没有子菜单则返回 null
# 分组管理
# 分组可选中
# setGroupCheckable
void setGroupCheckable(String groupId, boolean checkable, boolean exclusive)
设置分组的可选中状态,通常用于实现单选菜单。
参数:
groupId- 分组 IDcheckable- 是否可选中exclusive- 是否为互斥选择(单选模式),设置为 true 时同一分组中只能选中一个
单选示例:
menu.add("item1", "选项1", "group1").setChecked(true);
menu.add("item2", "选项2", "group1").setChecked(false);
menu.add("item3", "选项3", "group1").setChecked(false);
// 设置为单选模式(互斥选择)
menu.setGroupCheckable("group1", true, true);
# 分组可见性
# setGroupVisible
void setGroupVisible(String groupId, boolean visible)
设置分组的可见性。
参数:
groupId- 分组 IDvisible- 是否可见
示例:
// 隐藏整个分组
menu.setGroupVisible("group1", false);
# 分组启用状态
# setGroupEnabled
void setGroupEnabled(String groupId, boolean enabled)
设置分组的启用状态。
参数:
groupId- 分组 IDenabled- 是否启用
示例:
// 禁用整个分组
menu.setGroupEnabled("group1", false);
# 分组分割线
# setGroupDividerEnabled
void setGroupDividerEnabled(boolean groupDividerEnabled)
设置是否显示分组分隔线。不同分组之间会显示分割线。
参数:
groupDividerEnabled- 是否显示分隔线
示例:
menu.add("item1", "菜单项1");
menu.add("item2", "菜单项2");
menu.add("item3", "菜单项3", "group1");
menu.add("item4", "菜单项4", "group1");
// 启用分组分割线,未分组的菜单项和 group1 之间会显示分割线
menu.setGroupDividerEnabled(true);
# 显示和关闭
# show
void show()
显示弹出菜单。菜单将相对于锚点视图显示,具体位置取决于对齐方式设置。
# dismiss
void dismiss()
关闭弹出菜单。
# 对齐方式
# setGravity
void setGravity(int gravity)
设置弹出菜单的对齐方式。
参数:
gravity- 对齐方式,使用 Gravity 常量Gravity.START- 开始对齐Gravity.END- 结束对齐Gravity.TOP- 顶部对齐Gravity.BOTTOM- 底部对齐- 可以使用
|组合多个方向
示例:
PluginPopupMenu popupMenu = pluginUI.createPopupMenu(anchorView);
popupMenu.setGravity(Gravity.END | Gravity.BOTTOM);
popupMenu.show();
# getGravity
int getGravity()
获取弹出菜单的对齐方式。
返回值: 对齐方式常量值
# 事件监听
# setOnMenuItemClickListener
void setOnMenuItemClickListener(PluginMenu.OnMenuItemClickListener listener)
设置菜单项点击监听器。
参数:
listener- 点击监听器,null 表示移除监听器
监听器接口:
interface OnMenuItemClickListener {
boolean onMenuItemClick(PluginMenuItem item);
}
返回值:
true- 表示已处理该点击事件false- 表示未处理
示例:
popupMenu.setOnMenuItemClickListener(item -> {
String id = item.getItemId();
String title = item.getTitle().toString();
pluginUI.showToast("点击了:" + title);
// 处理点击事件
if ("copy".equals(id)) {
// 复制操作
} else if ("paste".equals(id)) {
// 粘贴操作
}
return true; // 已处理事件
});
# setOnDismissListener
void setOnDismissListener(OnDismissListener listener)
设置菜单关闭监听器。
参数:
listener- 关闭监听器,null 表示移除监听器
监听器接口:
interface OnDismissListener {
void onDismiss(PluginPopupMenu menu);
}
示例:
popupMenu.setOnDismissListener(menu -> {
pluginUI.showToast("菜单已关闭");
});
# 本地化文本支持
弹出菜单的标题支持 {key} 格式的本地化文本引用,但 ID 不会转换,始终保持原样。
示例:
// 菜单项标题使用本地化文本
menu.add("{copy}"); // ID 是 "{copy}",标题会转为本地化文本
menu.add("paste", "{paste}"); // ID 是 "paste",标题会转为本地化文本
// 子菜单标题
PluginSubMenu subMenu = menu.addSubMenu("{submenu_title}");
// 子菜单的 ID 是 "{submenu_title}",标题会转为本地化文本
assets/strings.mtl:
copy: Copy
paste: Paste
submenu_title: More Options
assets/strings-zh-CN.mtl:
copy: 复制
paste: 粘贴
submenu_title: 更多选项
提示:关于本地化文本的详细说明请查看 本地化文本。
# 完整示例
# 基本菜单
button.setOnClickListener(view -> {
PluginPopupMenu popupMenu = pluginUI.createPopupMenu(view);
PluginMenu menu = popupMenu.getMenu();
menu.add("{menu1}", "菜单1");
menu.add("{menu2}"); // ID 是 "{menu2}",标题会转为本地化文本
menu.add("菜单3"); // ID 和标题都是 "菜单3"
popupMenu.setOnMenuItemClickListener(item -> {
pluginUI.showToast("点击了:" + item.getTitle());
return true;
});
popupMenu.show();
});
# 图标菜单
button.setOnClickListener(view -> {
PluginPopupMenu popupMenu = pluginUI.createPopupMenu(view);
PluginMenu menu = popupMenu.getMenu();
menu.add("search", "搜索").setIcon(MaterialIcons.get("search"));
menu.add("copy", "复制").setIcon(MaterialIcons.get("content_copy"));
menu.add("cut", "剪切").setIcon(MaterialIcons.get("content_cut"));
menu.add("delete", "删除").setIcon(MaterialIcons.get("delete"));
popupMenu.setOnMenuItemClickListener(item -> {
pluginUI.showToast("点击了:" + item.getTitle());
return true;
});
popupMenu.show();
});
# 多选菜单
Set<String> checkedItems = new HashSet<>();
button.setOnClickListener(view -> {
PluginPopupMenu popupMenu = pluginUI.createPopupMenu(view);
PluginMenu menu = popupMenu.getMenu();
menu.add("option1", "选项1")
.setCheckable(true)
.setChecked(checkedItems.contains("option1"));
menu.add("option2", "选项2")
.setCheckable(true)
.setChecked(checkedItems.contains("option2"));
menu.add("option3", "选项3")
.setCheckable(true)
.setChecked(checkedItems.contains("option3"));
popupMenu.setOnMenuItemClickListener(item -> {
// 切换选中状态
if (item.isChecked()) {
checkedItems.remove(item.getItemId());
item.setChecked(false);
} else {
checkedItems.add(item.getItemId());
item.setChecked(true);
}
return true;
});
popupMenu.show();
});
提示:多选菜单不需要使用
setGroupCheckable(),直接为每个菜单项设置setCheckable(true)即可。
# 单选菜单
String[] currentSelection = {"option1"}; // 当前选中的选项
button.setOnClickListener(view -> {
PluginPopupMenu popupMenu = pluginUI.createPopupMenu(view);
PluginMenu menu = popupMenu.getMenu();
menu.add("option1", "选项1", "group1")
.setChecked(currentSelection[0].equals("option1"));
menu.add("option2", "选项2", "group1")
.setChecked(currentSelection[0].equals("option2"));
menu.add("option3", "选项3", "group1")
.setChecked(currentSelection[0].equals("option3"));
// 设置为单选模式(互斥选择)
menu.setGroupCheckable("group1", true, true);
popupMenu.setOnMenuItemClickListener(item -> {
item.setChecked(true);
currentSelection[0] = item.getItemId();
pluginUI.showToast("选中了:" + item.getTitle());
return true;
});
popupMenu.show();
});
# 多级菜单
button.setOnClickListener(view -> {
PluginPopupMenu popupMenu = pluginUI.createPopupMenu(view);
PluginMenu menu = popupMenu.getMenu();
// 创建第一个子菜单
PluginSubMenu subMenu1 = menu.addSubMenu("submenu1", "子菜单1");
subMenu1.add("sub1_0", "子项0");
subMenu1.add("sub1_1", "子项1");
subMenu1.add("sub1_2", "子项2");
// 创建第二个子菜单
PluginSubMenu subMenu2 = menu.addSubMenu("submenu2", "子菜单2");
subMenu2.add("sub2_0", "子项0");
subMenu2.add("sub2_1", "子项1");
subMenu2.add("sub2_2", "子项2");
// 添加普通菜单项
menu.add("menu3", "菜单项3");
menu.add("menu4", "菜单项4");
popupMenu.setOnMenuItemClickListener(item -> {
if (!item.hasSubMenu()) { // 避免展开子菜单时也弹出提示
pluginUI.showToast("点击了:" + item.getTitle());
}
return true;
});
popupMenu.show();
});
# 分割线
button.setOnClickListener(view -> {
PluginPopupMenu popupMenu = pluginUI.createPopupMenu(view);
PluginMenu menu = popupMenu.getMenu();
// 未分组的菜单项
menu.add("menu1", "菜单项1");
menu.add("menu2", "菜单项2");
// 分组的菜单项
menu.add("menu3", "菜单项3", "group1");
menu.add("menu4", "菜单项4", "group1");
// 启用分组分割线
menu.setGroupDividerEnabled(true);
popupMenu.setOnMenuItemClickListener(item -> {
pluginUI.showToast("点击了:" + item.getTitle());
return true;
});
popupMenu.show();
});
# 相关接口
- PluginUI - 插件UI核心
- PluginView - 插件视图
← API - 对话框 API - 设置界面 →