是否可以在PopupMenu中显示图标?

Zso*_*agy 48 android android-3.0-honeycomb

我非常喜欢我们在3.0中获得的新PopupMenu,但我无法在其中显示菜单项旁边的任何图标.我正在从下面的.xml中填充菜单:

<item android:id="@+id/menu_delete_product"
    android:icon="@drawable/sym_action_add"
    android:title="delete"
    android:showAsAction="ifRoom|withText" />

<item android:id="@+id/menu_modify_product"
    android:icon="@drawable/sym_action_add"
    android:title="modify"
    android:showAsAction="ifRoom|withText" />

<item android:id="@+id/menu_product_details"
    android:icon="@drawable/sym_action_add"
    android:title="details"
    android:showAsAction="ifRoom|withText" />
Run Code Online (Sandbox Code Playgroud)

使用此代码:

image.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        PopupMenu pop = new PopupMenu(getActivity(), v);
        pop.getMenuInflater().inflate(R.menu.shelves_details_menu, pop.getMenu());
        pop.show();
    }
});
Run Code Online (Sandbox Code Playgroud)

我不能让图标出现,我错过了什么?

小智 68

对Gaelan Bolger提供的解决方案的贡献.如果您收到"IllegalAccessException:访问不允许的字段",请使用此代码.

PopupMenu popup = new PopupMenu(mContext, view);

try {
    Field[] fields = popup.getClass().getDeclaredFields();
    for (Field field : fields) {
        if ("mPopup".equals(field.getName())) {
            field.setAccessible(true);
            Object menuPopupHelper = field.get(popup);
            Class<?> classPopupHelper = Class.forName(menuPopupHelper
                    .getClass().getName());
            Method setForceIcons = classPopupHelper.getMethod(
                    "setForceShowIcon", boolean.class);
            setForceIcons.invoke(menuPopupHelper, true);
            break;
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}

prepareMenu(popup.getMenu());
popup.show();
Run Code Online (Sandbox Code Playgroud)

文本

  • 我弄清楚了,我对proguard配置并不熟悉,只是反复试验.添加了以下2个规则后,代码在启用proguard时再次运行.(注意,我使用支持包中的PopupMenu)-keepclassmembernames类android.support.v7.widget.PopupMenu {private android.support.v7.internal.view.menu.MenuPopupHelper mPopup; -keepclassmembernames类android.support.v7.internal.view.menu.MenuPopupHelper {public void setForceShowIcon(boolean); } (4认同)

Rob*_*ert 29

如果您愿意冒险一点,请查看Google的PopupMenu源代码.创建自己的类,即MyPopupMenu,与Google的PopupMenu类相同,但稍作修改.

在PopupMenu的构造函数中:

public MyPopupMenu(Context context, View anchor) {
    // TODO Theme?
    mContext = context;
    mMenu = new MenuBuilder(context);
    mMenu.setCallback(this);
    mAnchor = anchor;
    mPopup = new MenuPopupHelper(context, mMenu, anchor);
    mPopup.setCallback(this);
    mPopup.setForceShowIcon(true); //ADD THIS LINE

}
Run Code Online (Sandbox Code Playgroud)

使用方法setForceShowIcon强制它显示图标.您也可以根据需要公开一个公共方法来设置此标志.

  • 在Android上"进入内部"有什么问题?这就是Android的全部意义 - 这不是iOS.很好的答案,谢谢@Robert! (6认同)
  • 你需要进入内部才能创建自己的PopupMenu,所以这不是一个好主意. (3认同)
  • 这里如何在androidx中获取“MenuBuilder”的实例? (3认同)

小智 19

我能够使用反射显示图标.它可能不是最优雅的解决方案,但它的工作原理.

            try {
                Class<?> classPopupMenu = Class.forName(popupMenu
                        .getClass().getName());
                Field mPopup = classPopupMenu.getDeclaredField("mPopup");
                mPopup.setAccessible(true);
                Object menuPopupHelper = mPopup.get(popupMenu);
                Class<?> classPopupHelper = Class.forName(menuPopupHelper
                        .getClass().getName());
                Method setForceIcons = classPopupHelper.getMethod(
                        "setForceShowIcon", boolean.class);
                setForceIcons.invoke(menuPopupHelper, true);
            } catch (Exception e) {
                e.printStackTrace();
            }
Run Code Online (Sandbox Code Playgroud)


Sar*_*oev 17

我们可以使用子菜单模型.因此,我们不需要编写显示弹出菜单的方法,它将自动显示.看一看:

menu.xml文件

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

<item
    android:id="@+id/action_more"
    android:icon="@android:drawable/ic_menu_more"
    android:orderInCategory="1"
    android:showAsAction="always"
    android:title="More">
    <menu>
        <item
            android:id="@+id/action_one"
            android:icon="@android:drawable/ic_popup_sync"
            android:title="Sync"/>
        <item
            android:id="@+id/action_two"
            android:icon="@android:drawable/ic_dialog_info"
            android:title="About"/>
    </menu>
</item>
</menu>
Run Code Online (Sandbox Code Playgroud)

在MainActivity.java中

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);   
    return true;
}
Run Code Online (Sandbox Code Playgroud)

结果是:

结果

  • 但是你需要两步才能进入子菜单. (3认同)

小智 11

在使用方法popup.show()之前,创建一个MenuPopupHelper实例并调用方法setForceShowIcon(true),就像这样

    try {
        Field mFieldPopup=popupMenu.getClass().getDeclaredField("mPopup");
        mFieldPopup.setAccessible(true);
        MenuPopupHelper mPopup = (MenuPopupHelper) mFieldPopup.get(popupMenu);
        mPopup.setForceShowIcon(true);
    } catch (Exception e) {

    }
Run Code Online (Sandbox Code Playgroud)


Aja*_*van 8

我找到的最简单的方法是使用MenuBuilderMenuPopupHelper.

MenuBuilder menuBuilder =new MenuBuilder(this);
MenuInflater inflater = new MenuInflater(this);
inflater.inflate(R.menu.menu, menuBuilder);
MenuPopupHelper optionsMenu = new MenuPopupHelper(this, menuBuilder, view);
optionsMenu.setForceShowIcon(true);
// Set Item Click Listener
menuBuilder.setCallback(new MenuBuilder.Callback() {
    @Override
    public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
        switch (item.getItemId()) {
            case R.id.opt1: // Handle option1 Click
                return true;
            case R.id.opt2: // Handle option2 Click
                return true;
            default:
                return false;
        }
    }

    @Override
    public void onMenuModeChange(MenuBuilder menu) {}
});


// Display the menu
optionsMenu.show();
Run Code Online (Sandbox Code Playgroud)

menu.xml文件

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/opt1"
        android:icon="@mipmap/ic_launcher"
        android:title="option 1" />
    <item
        android:id="@+id/opt2"
        android:icon="@mipmap/ic_launcher"
        android:title="option 2" />
</menu>
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Ily*_*man 6

我找到了一个原生的解决方案,使用MenuPopupHelper.setForceShowIcon(true).

private void createMenu(int menuRes, View anchor, MenuBuilder.Callback callback) {
    Context context = anchor.getContext();

    NavigationMenu navigationMenu = new NavigationMenu(context);
    navigationMenu.setCallback(callback);

    SupportMenuInflater supportMenuInflater = new SupportMenuInflater(context);
    supportMenuInflater.inflate(menuRes, navigationMenu);

    MenuPopupHelper menuPopupHelper = new MenuPopupHelper(context, navigationMenu, anchor);
    menuPopupHelper.setForceShowIcon(true);
    menuPopupHelper.show();
}
Run Code Online (Sandbox Code Playgroud)

用法

private void initMenu(View view) {
    view.findViewById(R.id.myButton).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            createMenu(R.menu.help_menu, view, new MenuBuilder.Callback() {
                @Override
                public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
                    switch (item.getItemId()) {
                        case R.id.id1:
                            // Do something
                            break;
                        case R.id.id2:
                            // Do something
                            break;
                        case R.id.id3:
                            // Do something
                            break;
                    }
                    return true;
                }

                @Override
                public void onMenuModeChange(MenuBuilder menu) {

                }
            });
        }
    });
}
Run Code Online (Sandbox Code Playgroud)