9

My menu xml code menu.xml:

<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Single menu item 
     Set id, icon and Title for each menu item
-->

 <item android:id="@+id/back"
      android:icon="@drawable/back1"
        android:showAsAction="never"
      android:title="Back" />

<item android:id="@+id/My_Profile"
      android:icon="@drawable/myprofile"
       android:showAsAction="never"
      android:title="My Profile" />

<item android:id="@+id/Job_Alert"
      android:icon="@drawable/jobalert4"
       android:showAsAction="never"
      android:title="Job Alert !" />

<item android:id="@+id/saved_job"
      android:icon="@drawable/jobapplied"
      android:title="Saved Jobs"
       />


<item android:id="@+id/Logout"
      android:icon="@drawable/logout"
      android:title="Logout" /> 
</menu>

I am calling menu xml like this

     PopupMenu popup = new PopupMenu(getBaseContext(), v);
 popup.getMenuInflater().inflate(R.menu.menu,  popup.getMenu());
     popup.show();

But it does not show the icon.

How can I set the icon on the popup menu?

Adam
  • 15,596
  • 5
  • 63
  • 102
Kuldeep
  • 331
  • 2
  • 7
  • 17

8 Answers8

12

You can create popup menu with icon using the MenuBuilder and MenuPopupHelper.

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

optionsMenu.show();

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>

enter image description here

Ajay Sivan
  • 1,895
  • 2
  • 22
  • 41
5

You can enable icons for popup menu by using Java reflection to call a hidden method as below:

public static void setForceShowIcon(PopupMenu popupMenu) {
    try {
        Field[] fields = popupMenu.getClass().getDeclaredFields();
        for (Field field : fields) {
            if ("mPopup".equals(field.getName())) {
                field.setAccessible(true);
                Object menuPopupHelper = field.get(popupMenu);
                Class<?> classPopupHelper = Class.forName(menuPopupHelper
                        .getClass().getName());
                Method setForceIcons = classPopupHelper.getMethod(
                        "setForceShowIcon", boolean.class);
                setForceIcons.invoke(menuPopupHelper, true);
                break;
            }
        }
    } catch (Throwable e) {
        e.printStackTrace();
    }
}
Bao Le
  • 13,726
  • 9
  • 59
  • 67
2

You could use reflection as described here: https://stackoverflow.com/a/18431605/4521603

Or if you use Xamarin / C#:

add:

using Java.Lang.Reflect;

Then use this in your code:

PopupMenu puMenu = new PopupMenu(Activity, v)

Field field = puMenu.Class.GetDeclaredField("mPopup");
field.Accessible = true;
Java.Lang.Object menuPopupHelper = field.Get(puMenu);
Method setForceIcons = menuPopupHelper.Class.GetDeclaredMethod("setForceShowIcon", Java.Lang.Boolean.Type);
setForceIcons.Invoke(menuPopupHelper, true);

puMenu.Inflate (Resource.Menu.your_actions);
puMenu.Show ();
Community
  • 1
  • 1
René AD
  • 195
  • 1
  • 8
1

Use this:

/**
 * Copied from android.support.v7.widget.PopupMenu.
 * "mPopup.setForceShowIcon(true);" in the constructor does the trick :)
 * 
 * @author maikvlcek
 * @since 5:00 PM - 1/27/14
 */
public class IconizedMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
        private Context mContext;
        private MenuBuilder mMenu;
        private View mAnchor;
        private MenuPopupHelper mPopup;
        private OnMenuItemClickListener mMenuItemClickListener;
        private OnDismissListener mDismissListener;

        /**
         * Callback interface used to notify the application that the menu has closed.
         */
        public interface OnDismissListener {
            /**
             * Called when the associated menu has been dismissed.
             *
             * @param menu The PopupMenu that was dismissed.
             */
            public void onDismiss(IconizedMenu menu);
        }

        /**
         * Construct a new PopupMenu.
         *
         * @param context Context for the PopupMenu.
         * @param anchor Anchor view for this popup. The popup will appear below the anchor if there
         *               is room, or above it if there is not.
         */
        public IconizedMenu(Context context, View anchor) {
            mContext = context;
            mMenu = new MenuBuilder(context);
            mMenu.setCallback(this);
            mAnchor = anchor;
            mPopup = new MenuPopupHelper(context, mMenu, anchor);
            mPopup.setCallback(this);
            mPopup.setForceShowIcon(true);
        }

        /**
         * @return the {@link android.view.Menu} associated with this popup. Populate the returned Menu with
         * items before calling {@link #show()}.
         *
         * @see #show()
         * @see #getMenuInflater()
         */
        public Menu getMenu() {
            return mMenu;
        }

        /**
         * @return a {@link android.view.MenuInflater} that can be used to inflate menu items from XML into the
         * menu returned by {@link #getMenu()}.
         *
         * @see #getMenu()
         */
        public MenuInflater getMenuInflater() {
            return new SupportMenuInflater(mContext);
        }

        /**
         * Inflate a menu resource into this PopupMenu. This is equivalent to calling
         * popupMenu.getMenuInflater().inflate(menuRes, popupMenu.getMenu()).
         * @param menuRes Menu resource to inflate
         */
        public void inflate(int menuRes) {
            getMenuInflater().inflate(menuRes, mMenu);
        }

        /**
         * Show the menu popup anchored to the view specified during construction.
         * @see #dismiss()
         */
        public void show() {
            mPopup.show();
        }

        /**
         * Dismiss the menu popup.
         * @see #show()
         */
        public void dismiss() {
            mPopup.dismiss();
        }

        /**
         * Set a listener that will be notified when the user selects an item from the menu.
         *
         * @param listener Listener to notify
         */
        public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
            mMenuItemClickListener = listener;
        }

        /**
         * Set a listener that will be notified when this menu is dismissed.
         *
         * @param listener Listener to notify
         */
        public void setOnDismissListener(OnDismissListener listener) {
            mDismissListener = listener;
        }

        /**
         * @hide
         */
        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
            if (mMenuItemClickListener != null) {
                return mMenuItemClickListener.onMenuItemClick(item);
            }
            return false;
        }

        /**
         * @hide
         */
        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
            if (mDismissListener != null) {
                mDismissListener.onDismiss(this);
            }
        }

        /**
         * @hide
         */
        public boolean onOpenSubMenu(MenuBuilder subMenu) {
            if (subMenu == null) return false;

            if (!subMenu.hasVisibleItems()) {
                return true;
            }

            // Current menu will be dismissed by the normal helper, submenu will be shown in its place.
            new MenuPopupHelper(mContext, subMenu, mAnchor).show();
            return true;
        }

        /**
         * @hide
         */
        public void onCloseSubMenu(SubMenuBuilder menu) {
        }

        /**
         * @hide
         */
        public void onMenuModeChange(MenuBuilder menu) {
        }

        /**
         * Interface responsible for receiving menu item click events if the items themselves
         * do not have individual item click listeners.
         */
        public interface OnMenuItemClickListener {
            /**
             * This method will be invoked when a menu item is clicked if the item itself did
             * not already handle the event.
             *
             * @param item {@link MenuItem} that was clicked
             * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
             */
            public boolean onMenuItemClick(MenuItem item);
        }

}

Source: https://gist.github.com/mediavrog/9345938

Cícero Moura
  • 1,391
  • 1
  • 17
  • 30
  • I tried using this class and got an exception while showing popup menu. java.lang.RuntimeException: Failed to resolve attribute at index 6 – Saurabh Mar 13 '15 at 12:03
  • Usage of this class, as mentioned by @kevinkl3 on comment : `public void showPopup(View v) { IconizedMenu popup = new IconizedMenu(this, v); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.menu_myactivity, popup.getMenu()); popup.show(); }` – Amal Apr 01 '17 at 13:12
1

before popupMenu.show(); use

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

                }
Gil Snovsky
  • 172
  • 1
  • 6
0

It's because when you use the showAsAction="never" attribute, the default overflow does not return your icon. You could create your own overflow like this:

<item android:title=""
        android:id="@+id/overflow"
        android:showAsAction="always"
        android:icon="@drawable/overflow_icon">
  <menu >    
    <item android:id="@+id/back"
          android:icon="@drawable/back1"
          android:title="Back" />

    <item android:id="@+id/My_Profile"
          android:icon="@drawable/myprofile"
          android:title="My Profile" />

    <item android:id="@+id/Job_Alert"
          android:icon="@drawable/jobalert4"
          android:title="Job Alert !" />

    <item android:id="@+id/saved_job"
          android:icon="@drawable/jobapplied"
          android:title="Saved Job"/>
    <item android:id="@+id/Logout"
          android:icon="@drawable/logout"
          android:title="Logout" /> 
  </menu>
</item>
Rakeeb Rajbhandari
  • 4,853
  • 6
  • 41
  • 74
0

if trying this code in any activity then replace getbBaseContext() with this i.e activity context

PopupMenu popup = new PopupMenu(this, v);
Sush
  • 3,784
  • 1
  • 14
  • 34
0

You can implement this By the use of Reflection if u don`t familiar with it with the help of this awesome java advanced feature u can modify the runtime behavior of applications running in the JVM you can look at the object and perform its methods on runtime and in our case we need to modify popupMenu behavior at runtime instead of extend the core class and modify it ;) hope that help Try my method working like a charm

private void showPopupMenu(View view) {
    // inflate menu
    PopupMenu popup = new PopupMenu(mcontext, view);
    MenuInflater inflater = popup.getMenuInflater();
    inflater.inflate(R.menu.main, popup.getMenu());

    Object menuHelper;
    Class[] argTypes;
    try {
        Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
        fMenuHelper.setAccessible(true);
        menuHelper = fMenuHelper.get(popup);
        argTypes = new Class[]{boolean.class};
        menuHelper.getClass().getDeclaredMethod("setForceShowIcon", argTypes).invoke(menuHelper, true);
    } catch (Exception e) {

    }
    popup.show();




} 
Mohamed Ayed
  • 417
  • 5
  • 7