Как это странное состояние возникает, когда значок пункта меню отображается в меню переполнения панели инструментов?

Я хочу показать дополнительное меню на панели инструментов (AppCompat-v7:22.1.1), ниже мой 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" />

После запуска моего приложения значок пункта меню не отображается, затем я попробовал это solution, добавьте метод переопределения onMenuOpened() в мою активность (расширяется от 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);
}

Но после запуска этой демонстрации я обнаружил, что значок по-прежнему не отображается.

1. Меню с нажатием кнопки переполнения

Из этой сообщенной проблемы я знаю, что AppCompatActivity.onMenuOpened не вызывается больше в 22.x, но странно, что когда я нажимаю клавишу аппаратного меню в Genymotion, меню появляется внизу и со значком,

2. Меню с нажатием клавиши меню

после закрытия меню я снова нажимаю кнопку переполнения на панели инструментов, появляются эти значки в меню,

3. Меню с нажатием кнопки переполнения

как это странно! Почему это происходит?


person wqycsu    schedule 06.05.2015    source источник


Ответы (4)


Для AppCompactActivity вы вместо этого можно поставить эту проверку на onPrepareOptionsPanel().

@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);
}
person Alécio Carvalho    schedule 19.05.2015
comment
Это может быть дело вкуса, но я думаю, что if (menu.getClass().equals(MenuBuilder.class)) элегантнее, чем if (menu.getClass().getSimpleName().equals("MenuBuilder")). Чем меньше жестко закодированных строк, тем лучше ИМХО ;-) - person Matthias; 07.07.2015
comment
Игнорируйте мой комментарий. Делая это по-своему, он работает как для родного Android MenuBuilder, так и для AppCompat. Хорошая работа! - person Matthias; 07.07.2015
comment
если вы используете это и proguard, вам нужно будет исключить соответствующие классы: -keep class android.support.v7.view.menu.MenuBuilder {*;} -keep class com.android.view.menu.MenuBuilder {*;} - person farkerhaiku; 01.08.2018
comment
Как насчет фрагментов и действий, которые не расширяют совместимость приложений? - person MMG; 19.08.2020

Вот модификация отличного ответа, предоставленного выше Алесио Карвалью. Эта модификация на тот случай, если нужно корректно отображать иконки не в основной панели действий приложения, а в настраиваемых панелях инструментов внутри каждого отдельного фрагмента (я хотел отдельную панель инструментов со своим заголовком и своим настроенным действием меню для каждого фрагмента, а не просто добавление новых элементов в панель действий общей AppCompatActivity).

Для указанного случая класс Fragment выглядит следующим образом:

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;
   }
}

Затем my_fragment_layout.xml включил меню следующим образом

<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>

Типичный файл меню был реализован как res/menu/my_fragment_menu.xml. Фрагмент был добавлен в макет mainActivity просто как

<fragment android:id="@+id/my_fragment_id"
android:name="com.appspot.trendy.trendychart.MyFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
person Elia12345    schedule 31.07.2016
comment
Браво! Этот ответ также иллюстрирует более общий вопрос о том, как развернуть ToolBar внутри Fragment с setHasOptionsMenu(false);. IE: как сделать системы меню Activity и Fragment полностью обособленными. - person Bad Loser; 11.12.2020

@SuppressLint("RestrictedApi")
public void initToolBar(){    
    MenuBuilder menuBuilder = (MenuBuilder) toolbar.getMenu();
    menuBuilder.setOptionalIconsVisible(true);
}

Я решил это так.

введите здесь описание изображения

person 郑松岚    schedule 27.06.2018
comment
Что вы делаете для чередования белого и черного цветов? Используйте всегда/никогда вместо ifRoom, чтобы заставить их куда идти? - person Andrew67; 23.09.2018

это работает для меня

  @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;
    }
person Charles-Qx    schedule 28.04.2021