How does this strange condition happens when show menu item icon in toolbar overflow menu?
Asked Answered
M

4

11

I want to show a overflow menu in toolbar(AppCompat-v7:22.1.1), below is my menu_main.xml.

<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_search"
    android:title="@string/action_search"
    android:icon="@mipmap/ic_menu_search"
    android:orderInCategory="100"
    android:actionViewClass="android.widget.SearchView"
    app:showAsAction="ifRoom"/>

<item
    android:id="@+id/menu_group_chat"
    android:title="@string/menu_group_chat"
    android:icon="@mipmap/ic_menu_groupchat" />

<item
    android:id="@+id/menu_add_friend"
    android:title="@string/menu_add_friend"
    android:icon="@mipmap/ic_menu_add_friend" />

After running my app, the icon of menu item is not displayed, then I tried this solution, add an override method onMenuOpened() in my Activty(extends from AppCompatActivity),

@Override
public boolean onMenuOpened(int featureId, Menu menu) {
    if(menu!=null){
        if(menu.getClass().getSimpleName().equals("MenuBuilder")){
            try {
                Method m = menu.getClass().getDeclaredMethod(
                        "setOptionalIconsVisible", Boolean.TYPE);
                m.setAccessible(true);
                m.invoke(menu, true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    return super.onMenuOpened(featureId, menu);
}

But after running this demo, I find that the icon is still not displayed.

1. Menu with overflow button click

From this reported issue, I know that AppCompatActivity.onMenuOpened is not called any more in 22.x, but it's odd that when I click the hardware menu key in Genymotion, the menu appear at the bottom and with the icon,

2. Menu with menu key click

after closing the menu, I click the overflow button in the toolbar again, these icons in menu appear,

3. Menu with overflow button click

how strange it is! Why this happens?

Mcallister answered 6/5, 2015 at 12:12 Comment(0)
D
31

For the AppCompactActivity you can put this check on the onPrepareOptionsPanel() instead.

@Override
protected boolean onPrepareOptionsPanel(View view, Menu menu) {
        if (menu != null) {
            if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
                try {
                    Method m = menu.getClass().getDeclaredMethod(
                            "setOptionalIconsVisible", Boolean.TYPE);
                    m.setAccessible(true);
                    m.invoke(menu, true);
                } catch (Exception e) {
                    Log.e(getClass().getSimpleName(), "onMenuOpened...unable to set icons for overflow menu", e);
                }
            }
        }
    return super.onPrepareOptionsPanel(view, menu);
}
Dominion answered 19/5, 2015 at 23:10 Comment(5)
It may be a matter of taste but I think if (menu.getClass().equals(MenuBuilder.class)) is more elegant than if (menu.getClass().getSimpleName().equals("MenuBuilder")). The less hardcoded strings the better IMHO ;-)Dishtowel
Ignore my comment. Doing it your way makes it works for both Android's native MenuBuilder and AppCompat's. Nice job!Dishtowel
if you use this and proguard, you'll need to exclude appropriate classes: -keep class android.support.v7.view.menu.MenuBuilder {*;} -keep class com.android.view.menu.MenuBuilder {*;}Peregrine
What about fragments and activities that don't extend appcompatactivity?Antoniaantonie
I had to switch to the method public boolean onCreateOptionsMenu(Menu menu) the rest stayed the same.Friedlander
K
3

this is works for me

  @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.my_menu, menu);

        //this section is the one that allows to visualize the icon
        if(menu instanceof MenuBuilder){
            MenuBuilder m = (MenuBuilder) menu;
            //noinspection RestrictedApi
            m.setOptionalIconsVisible(true);
        }

        return true;
    }
Kristikristian answered 28/4, 2021 at 6:48 Comment(1)
Works! Just add @SuppressLint("RestrictedApi") above the @Override)Friedlander
L
1

Here is a modification of the excellent answer provided above by Alécio Carvalho. This modification is for the case if it is necessary to correctly show icons not in the main app's action bar, but in custom toolbars inside each separate fragment (I wanted a separate toolbar with own title and own customized action menu for every fragment, not simply adding new items to the action bar of the overall AppCompatActivity).

For the mentioned case the Fragment class is as follows:

public class MyFragment extends android.support.v4.app.Fragment {
...
   public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        //at first get the very toolbar
        fragmentToolbar = (Toolbar) view.findViewById(R.id.fragment_toolbar);
        fragmentToolbar.setTitle(R.string.title_string);
        fragmentToolbar.showOverflowMenu();

        //now ready to  get the menu's method, which is responsible for icons, and change its properties 
        Menu menu=fragmentToolbar.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();
        }

        //now all the other stuff necessary for the toolbar operation
        fragmentToolbar.inflateMenu(R.menu.my_fragment_menu);
        fragmentToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem arg0) {
                if(arg0.getItemId() == R.id.menu_item_1){
                   ...
                }
                return false;
            }
        });

        //and now the main stuff of onCreateView
        View view = inflater.inflate(R.layout.my_fragment_layout, container, false);
        return view;
   }
}

Then my_fragment_layout.xml included menu as follows

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar    xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:id="@+id/fragment_toolbar"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:elevation="4dp">
    </android.support.v7.widget.Toolbar>

//...other items

</LinearLayout>

A typical menu file was implemented as res/menu/my_fragment_menu.xml. The fragment was added in the mainActivity's layout simply as

<fragment android:id="@+id/my_fragment_id"
android:name="com.appspot.trendy.trendychart.MyFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Lictor answered 31/7, 2016 at 19:10 Comment(1)
Bravo! This answer also illustrates the more general issue of how to deploy a ToolBar inside of a Fragment having setHasOptionsMenu(false);. IE: How to keep the Activity and Fragment menu systems entirely discrete.Marchak
L
1
@SuppressLint("RestrictedApi")
public void initToolBar(){    
    MenuBuilder menuBuilder = (MenuBuilder) toolbar.getMenu();
    menuBuilder.setOptionalIconsVisible(true);
}

I solved it this way.

enter image description here

Lashaunda answered 27/6, 2018 at 7:50 Comment(1)
What do you do for the alternating white/black colors? Use always/never instead of ifRoom to force which ones go where?Gemstone

© 2022 - 2024 — McMap. All rights reserved.