Search code examples
androidpopupmenu

PopupMenu with icons displayed incorrectly - Android Studio


In higher SDKs like 33 the PopupMenu with Icons is displayed incorrectly: Wrong PopupMenu with Icons

I don't know what is wrong.

I created it like this:

//init the wrapper with style
Context wrapper = new ContextThemeWrapper(anchor.getContext(), R.style.MyPopupStyle);

//init the popup
PopupMenu popup = new PopupMenu(wrapper, anchor);

/*  The below code in try catch is responsible to display icons*/
if (isWithIcons) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        popup.setForceShowIcon(true);
    } else {
        try {
            Field[] fields = popup.getClass().getDeclaredFields();
            for (Field field : fields) {
                if ("mPopup".equals(field.getName())) {
                    field.setAccessible(true);
                    Object menuPopupHelper = field.get(popup);
                    assert menuPopupHelper != null;
                    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(menu, popup.getMenu());

popup.show();

I tried with SDK 23 and there it is displayed correctly: Correct PopupMenu with Icons


Solution

  • The following post did work for me: https://stackoverflow.com/a/41666520/18030070

    To center the image vertically, I used this class: https://stackoverflow.com/a/38788432/18030070

    /**
     * method responsible to show popup menu
     *
     * @param anchor      is a view where the popup will be shown
     * @param isWithIcons flag to check if icons to be shown or not
     * @param menu        menu items for popup menu
     */
    public static PopupMenu showPopupMenu(View anchor, boolean isWithIcons, @MenuRes int menu) {
        //init the wrapper with style
        Context wrapper = new ContextThemeWrapper(anchor.getContext(), R.style.MyPopupStyle);
    
        //init the popup
        PopupMenu popupMenu = new PopupMenu(wrapper, anchor);
    
        //inflate menu
        popupMenu.getMenuInflater().inflate(menu, popupMenu.getMenu());
    
        /*  The below code in try catch is responsible to display icons*/
        if (isWithIcons) {
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    
                insertMenuItemIcons(anchor.getContext(), popupMenu);
    
            } else {
                try {
                    Field[] fields = popupMenu.getClass().getDeclaredFields();
                    for (Field field : fields) {
                        if ("mPopup".equals(field.getName())) {
                            field.setAccessible(true);
                            Object menuPopupHelper = field.get(popupMenu);
                            assert menuPopupHelper != null;
                            Class<?> classPopupHelper = Class.forName(menuPopupHelper.getClass().getName());
                            Method setForceIcons = classPopupHelper.getMethod("setForceShowIcon", boolean.class);
                            setForceIcons.invoke(menuPopupHelper, true);
                            break;
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            }
    
        }
    
        return popupMenu;
    }