PopupMenu Icon doesn't show
Asked Answered
B

4

5

I create a ListView that has an PopupMenu in each item. I create a menu layout and use it as my PopupMenu. My problem is every time I clicked the ellipses option in the item of my ListView the PopupMenu is displayed with Text but the Icon is not showing up.

Here's my xml menu:

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

<item
    android:id="@+id/action_retry"
    android:icon="@drawable/retry"
    android:title="@string/retry"
    app:showAsAction="always"
    />
<item
    android:id="@+id/action_delete"
    android:icon="@drawable/delete"
    android:title="@string/delete"
    app:showAsAction="always"
    />
 </menu>

Then in my Adapter for my ListView is like this :

public class MyListViewAdapter extends BaseAdapter implements MenuItem.OnMenuItemClickListener {

.....

 @Override
public View getView(final int position, View convertView, ViewGroup parent) {

    if (convertView == null) {
        LayoutInflater inflater = activity.getLayoutInflater();
        convertView = inflater.inflate(R.layout.mylistrow, null);
    }

    final View action = (View) convertView.findViewById(R.id.action);

    action.setOnClickListener(new View.OnClickListener(){
        public void onClick(View v) {
            showPopup(action, position);
                      }
    });

    // ....codes for listview creation....

    return convertView;
}

public void showPopup(View v, int listItemPosition) {
    PopupMenu popup = new PopupMenu(mContext, v);
    MenuInflater inflater = popup.getMenuInflater();
    inflater.inflate(R.menu.outbox_menu, popup.getMenu());
    popup.show();
}

@Override
public boolean onMenuItemClick(MenuItem item) {

    switch (item.getItemId()) {
        case R.id.action_retry:

            return true;
        case R.id.action_delete:

            return true;
        default:
            return false;
    }
}

Thank you in advance for the help.

Blunger answered 26/5, 2017 at 7:18 Comment(1)
Same here my icon is not showing upSmallminded
B
14

I found a solution in this link and apply it to my code.

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();
    }
Blunger answered 26/5, 2017 at 8:26 Comment(1)
This way would work, however, if you're using proguard/dexguard in your project, this might not work on the release APK due to use of reflection.Epiphytotic
B
14

The MenuBuilder is a hidden class but does contain a method to show icons. You will need to use reflection to show the icons in the menu. Try adding this in showPopop(View, int):

PopupMenu popup = new PopupMenu(mContext, v);
try {
  Method method = popup.getMenu().getClass().getDeclaredMethod("setOptionalIconsVisible", boolean.class);
  method.setAccessible(true);
  method.invoke(popup.getMenu(), true);
} catch (Exception e) {
  e.printStackTrace();
}
Bradwell answered 26/5, 2017 at 7:28 Comment(4)
I updated the code and it should work now. This is what happens when answering questions at 12:40 AM. Hehe.Bradwell
It's late there (O_O) I hope you can take a rest soon. I tried the updated answer but is still doesn't show the icons. I'm still wondering why.Blunger
I looked at the source this morning. If you are using android.support.v7.widget.PopupMenu then my code would have worked because setOptionalIconsVisibility is public. In AOSP this method is package-private, so I added method.setAccessible(true); to my answer. Now it should work for both the support library and native PopupMenu.Bradwell
Is it possible to show icons without using reflection?Prendergast
B
14

I found a solution in this link and apply it to my code.

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();
    }
Blunger answered 26/5, 2017 at 8:26 Comment(1)
This way would work, however, if you're using proguard/dexguard in your project, this might not work on the release APK due to use of reflection.Epiphytotic
K
3

Use this instead of android.widget.PopupMenu

androidx.appcompat.widget.PopupMenu popupMenu = new PopupMenu(this,view, Gravity.END);
popupMenu.setForceShowIcon(true);
Kandicekandinsky answered 2/8, 2022 at 12:9 Comment(0)
A
0

In Kotlin

  val popup = PopupMenu(context, holder.img_menu)
        try {
            popup.inflate(R.menu.bank_edit_menu)
            val fields: Array<Field> = popup.javaClass.declaredFields
            for (field in fields) {
                if ("mPopup" == field.getName()) {
                    field.setAccessible(true)
                    val menuPopupHelper: Any = field.get(popup)
                    val classPopupHelper =
                        Class.forName(menuPopupHelper.javaClass.name)
                    val setForceIcons: Method = classPopupHelper.getMethod(
                        "setForceShowIcon",
                        Boolean::class.javaPrimitiveType
                    )
                    setForceIcons.invoke(menuPopupHelper, true)
                    break
                }
            }
            popup.setOnMenuItemClickListener(object : PopupMenu.OnMenuItemClickListener{
                override fun onMenuItemClick(p0: MenuItem?): Boolean {
                    Log.e(">>",p0.toString())
                    return true
                }

            })
            popup.show();

        } catch (e: Exception) {
            e.printStackTrace()
        }
Antony answered 29/10, 2020 at 6:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.