在AppCompat中的MenuPopupHelper类有@hide注解。如果这是一个问题,或者由于某种原因你无法使用AppCompat,那么可以使用另一种解决方案,即在MenuItem标题中使用一个包含图标和标题文本的Spannable。主要步骤如下:
- 用menu xml文件填充你的PopupMenu
- 如果任何一个item有图标,则对所有的items都进行以下操作:
- 如果该item没有图标,则创建一个透明图标。这可以确保没有图标的item与有图标的item对齐。
- 创建一个包含图标和标题的SpannableStringBuilder
- 将menuItem的标题设置为SpannableStringBuilder
- 将menuItem的图标设置为null,以防万一
优点:没有反射。不使用任何隐藏的api。可以与框架PopupMenu一起使用。
缺点:代码更多。如果你有一个没有图标的子菜单,在小屏幕上它将有不必要的左边距。
详细信息:
首先,在dimens.xml文件中定义图标的大小:
<dimen name="menu_item_icon_size">24dp</dimen>
接下来,我们介绍一些将XML定义的图标移动到标题中的方法:
public static void insertMenuItemIcons(Context context, PopupMenu popupMenu) {
Menu menu = popupMenu.getMenu();
if (hasIcon(menu)) {
for (int i = 0; i < menu.size(); i++) {
insertMenuItemIcon(context, menu.getItem(i));
}
}
}
private static boolean hasIcon(Menu menu) {
for (int i = 0; i < menu.size(); i++) {
if (menu.getItem(i).getIcon() != null) return true;
}
return false;
}
private static void insertMenuItemIcon(Context context, MenuItem menuItem) {
Drawable icon = menuItem.getIcon();
if (icon == null) icon = new ColorDrawable(Color.TRANSPARENT);
int iconSize = context.getResources().getDimensionPixelSize(R.dimen.menu_item_icon_size);
icon.setBounds(0, 0, iconSize, iconSize);
ImageSpan imageSpan = new ImageSpan(icon);
SpannableStringBuilder ssb = new SpannableStringBuilder(" " + menuItem.getTitle());
ssb.setSpan(imageSpan, 1, 2, 0);
menuItem.setTitle(ssb);
menuItem.setIcon(null);
}
最后,创建您的PopupMenu并在显示它之前使用上述方法:
PopupMenu popupMenu = new PopupMenu(view.getContext(), view);
popupMenu.inflate(R.menu.popup_menu);
insertMenuItemIcons(textView.getContext(), popupMenu);
popupMenu.show();
截图: