Is it possible to display icons in a PopupMenu?

I really like the new PopupMenu we got in 3.0, but I just can't display any icons next to the menu items in it. I'm inflating the menu from the .xml below:

<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" />

With this code:

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();
    }
});

I can't get the icons to show up, am I missing something?


Solution 1:

Contribution to the solution provided by Gaelan Bolger. Use this code if you get a "IllegalAccessException: access to field not allowed".

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();

text

Solution 2:

If you're willing to be a bit adventurous, look at Google's source code for PopupMenu. Create your own class i.e. MyPopupMenu that is the same as Google's PopupMenu class, but make one slight change.

In PopupMenu's constructor:

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

}

use the method setForceShowIcon to force it to show the icon. You can also just expose a public method to set this flag as well depending on your needs.

Solution 3:

I was able to show the icons using reflection. It may not be the most elegant solution but it works.

            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();
            }

Solution 4:

We can use sub-menu model. So, we don't need to write method for showing popup menu, it will be showing automacally. Have a look:

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>

in 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;
}

The result is:

Result

Solution 5:

before use method popup.show(),make a MenuPopupHelper instance and call method setForceShowIcon(true),like this

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

    }