12

I am trying to show a drop down menu for my toolbar which includes BOTH text and icons:

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

    <item
        android:id="@+id/menu_add"
        android:title="@string/menu.add"
        android:icon="@drawable/ic_add_black_24dp"
        app:showAsAction="always" />

    <item
        android:id="@+id/menu_edit"
        android:title="@string/menu.edit"
        android:icon="@drawable/ic_create_black_24dp"
        app:showAsAction="never" />

</menu>

The menu_add does show with the icon on the toolbar itself but the menu_edit only shows the text without the icon.

This answer: https://stackoverflow.com/a/19750717/197127 says that Google has removed it by design but does not refer to how you may override it.

Edit

I also need the device "menu" button to show the same menu.

Community
  • 1
  • 1
checklist
  • 12,340
  • 15
  • 58
  • 102

8 Answers8

10

I created something like this:

@SuppressLint("RestrictedApi")
fun Menu.showIcons() {
    (this as? MenuBuilder)?.setOptionalIconsVisible(true)
}

and it works basically on any menu.

For toolbar, you can override onPrepareOptionsMenu in activity or fragment and before calling super just call menu.showIcons() or you can use it with PopupMenu like so PopupMenu(requireContext(), anchor).menu.showIcons().

Kikju
  • 787
  • 1
  • 6
  • 17
  • I don't know why you didn't receive more upvotes. It's the only solution that worked for me, and it's the simplest of all. – Karzel Mar 01 '21 at 08:44
6

This Kotlin code worked for me. I used "popup.setForceShowIcon(true)"

val popup = PopupMenu(context, button);

popup.menuInflater.inflate(menuRes, popup.menu);

popup.setForceShowIcon(true)

The full code is written below

//R.menu.menu_popup -- Menu xml File
<menu
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_1"
        android:icon="@drawable/email"
        android:title="Email" />
    <item android:id="@+id/menu_2"
        android:icon="@drawable/phone"
        android:title="Phone" />
</menu>

// Inside Activity
findViewById<Button>(R.id.button1).setOnClickListener {
    show_PopUp_Menu(this, it, R.menu.menu_popup)
}


@SuppressLint("RestrictedApi")
fun show_PopUp_Menu(context: Context, button:Button, menuRes: Int) {

    val popup = PopupMenu(context, button)
    popup.menuInflater.inflate(menuRes, popup.menu)

    popup.setOnMenuItemClickListener { menuItem: MenuItem ->
        when(menuItem.itemId){
            R.id.menu_1->{
                Toast.makeText(this, "Menu 1 clicked", Toast.LENGTH_SHORT).show()
                true
            }
            R.id.menu_2->{
                Toast.makeText(this, "Menu 2 clicked", Toast.LENGTH_SHORT).show()
                true
            }
            else -> false
        }
    }
    
    popup.setOnDismissListener {
        // Respond to popup being dismissed.
    }
    popup.setForceShowIcon(true)
    popup.show()
}
Satish Singh
  • 71
  • 1
  • 2
  • popup.setForceShowIcon(true) ::: Call requires API level 29 (current min is XX): android.widget.PopupMenu#setForceShowIcon – SHS Aug 30 '22 at 12:18
5

Yes, its not being displayed in new versions of support library, but you can do the trick by adding submenu. (You can add it via both xml and code). like this:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_settings"
        android:icon="@drawable/abc_ic_menu_moreoverflow_mtrl_alpha"
        android:title="@string/action_settings"
        app:showAsAction="always">
        <menu>
            <item
                android:icon="@drawable/ic_event"
                android:title="@string/action_settings"
                app:showAsAction="always" />
            <item
                android:icon="@drawable/ic_event"
                android:title="@string/action_settings"
                app:showAsAction="always" />
        </menu>
    </item>
</menu>

Hope it helped:) Edit: see snapshots of above code:

menu => menu open

Harin
  • 2,413
  • 3
  • 15
  • 30
4

It doesnot work on android support v7 version but you can tweak this by modifying little bit. below code works for me

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">

<item
    android:id="@+id/action_settings"
    android:icon="@drawable/abc_ic_menu_moreoverflow_mtrl_alpha"
    android:title="@string/action_settings"
    app:showAsAction="always">
    <menu>

        <item
            android:id="@+id/action_rate"
            android:icon="@drawable/ic_grade_black_24dp"
            android:orderInCategory="100"
            android:title="@string/action_rate"
            app:showAsAction="never" />
        <item
            android:id="@+id/action_share"
            android:icon="@drawable/ic_share_black_24dp"
            android:orderInCategory="101"
            android:title="@string/action_share"
            app:showAsAction="never" />
        <item
            android:id="@+id/action_enquiry"
            android:icon="@drawable/ic_message_black_24dp"
            android:orderInCategory="102"
            android:title="@string/action_enquiry"
            app:showAsAction="never" />
        <item
            android:id="@+id/action_disclaimer"
            android:icon="@drawable/ic_info_black_24dp"
            android:orderInCategory="103"
            android:title="@string/action_disclaimer"
            app:showAsAction="never" />
    </menu>
</item>

yubaraj poudel
  • 3,821
  • 1
  • 31
  • 28
3

I found this solution: https://stackoverflow.com/a/30337653/197127. Basically, overriding a method and it does not break the device menu button or the overflow. Thanks to all.

Community
  • 1
  • 1
checklist
  • 12,340
  • 15
  • 58
  • 102
1

Try this

 MenuPopupHelper menuHelper = new MenuPopupHelper(getContext(), (MenuBuilder) 
 popupmenu.getMenu(), button);
 menuHelper.setForceShowIcon(true);
 menuHelper.show();

Worked for me.

Rahul sharma
  • 1,492
  • 12
  • 26
0

I created something like this: Try this:

    Menu menu= toolbar.getMenu();
    Method menuMethod = null;
    try {
       menuMethod = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
       menuMethod.setAccessible(true);
       menuMethod.invoke(menu, true);
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
0

From the Above 3.0 android icons in the pop menu are not displayed so you have to trick it and this works you can try

   //init the popup
   PopupMenu popup = new PopupMenu(context, anchor);
 
        /*  The below code in try catch is responsible to display icons*/
            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();
            }
 
        //inflate menu
        popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu());
 
        //show menu
        popup.show();
Stefano Sansone
  • 2,377
  • 7
  • 20
  • 39