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

Искам да покажа меню за препълване в лентата с инструменти (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" />

След стартиране на приложението ми иконата на елемент от менюто не се показва, след което опитах това решение, добавете метод за заместване 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")). Колкото по-малко твърдо кодирани низове, толкова по-добре IMHO ;-) - person Matthias; 07.07.2015
comment
Игнорирайте коментара ми. Правейки го по вашия начин, той работи както за родния MenuBuilder на Android, така и за 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

Ето модификация на отличния отговор, предоставен по-горе от Alécio Carvalho. Тази модификация е за случая, ако е необходимо да се показват правилно иконите не в лентата с действия на основното приложение, а в персонализирани ленти с инструменти във всеки отделен фрагмент (исках отделна лента с инструменти със собствено заглавие и собствено персонализирано действие меню за всеки фрагмент, а не просто добавяне на нови елементи към лентата с действия на цялостната 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