Popup menu with icon on Android
25,567
Solution 1
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>
Solution 2
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();
}
}
Solution 3
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 ();
Solution 4
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
Solution 5
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>
Author by
Kuldeep
Updated on September 18, 2020Comments
-
Kuldeep over 3 years
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?
-
Saurabh about 9 yearsI tried using this class and got an exception while showing popup menu. java.lang.RuntimeException: Failed to resolve attribute at index 6
-
iaindownie about 7 years+1 for neatest way I've seen of building an icon + text menu item. However, how have you handled the onItemClick method?
-
Ajay Sivan about 7 years@iaindownie I have added code to handle menu clicks. I think this may help you.
-
iaindownie about 7 yearsBrilliant, thanks! This should be the answer on all the other posts too! Far cleaner than everything else I've seen for custom/icon menus.
-
Amal about 7 yearsUsage 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(); }
-
Michael Kazarian over 6 yearsI have caught
MenuBuilder constructor can only be called from within the same library group
.