Как добавить меню параметров во фрагмент в Android

399

Я пытаюсь добавить пункт в меню параметров из группы фрагментов.

Я создал новый MenuFragmentкласс и расширил его для фрагментов, в которые я хочу включить пункт меню. Вот код:

Ява:

public class MenuFragment extends Fragment {

    MenuItem fav;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        fav = menu.add("add");
        fav.setIcon(R.drawable.btn_star_big_off);
    }
}

Котлин:

class MenuFragment : Fragment {

    lateinit var fav: MenuItem

    override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        fav = menu.add("add");
        fav.setIcon(R.drawable.btn_star_big_off);
    }
}

По некоторым причинам, onCreateOptionsMenuкажется, не работает.

misterbassman
источник
может быть глупый вопрос ... вы нажимаете кнопку меню справа?
Овидиу Латку
2
..lol ... да, я нажал кнопку меню, я также пробовал с и без: fav.setShowAsAction (MenuItem.SHOW_AS_ACTION_ALWAYS);
господин басист
Привет, может быть, эта тема поможет вам или проверьте API-демо для рабочего примера.
Камены

Ответы:

605

Вызовите супер метод:

Ява:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // TODO Add your menu entries here
        super.onCreateOptionsMenu(menu, inflater);
    }

Котлин:

    override fun void onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        // TODO Add your menu entries here
        super.onCreateOptionsMenu(menu, inflater)
    }

Поместите операторы журнала в код, чтобы увидеть, не вызывается ли метод или не изменяется ли меню вашим кодом.

Кроме того, убедитесь , что вы вызываете setHasOptionsMenu(boolean)в onCreate(Bundle)уведомить фрагмент , который он должен участвовать в обработке меню опций.

Каффс
источник
2
Спасибо за помощь, я добавил супер метод и понял, что удалил @Override, поэтому добавил его обратно, затмение выдало ошибку, поэтому я заменил MenuInflater для импорта android.view.MenuInflater; вместо импорта android.support.v4.view.MenuInflater; и теперь все работает
господин басист
183
не вызывает setHasOptionsMenu (true) в onCreate фрагмента получил меня дважды сейчас
joshkendrick
7
Я переносил свою активность во фрагмент и столкнулся с этой проблемой. Подпись метода изменилась с public boolean на public void, и аргументы также изменились. Обязательно примите это к сведению!
you786
14
Обратите внимание, что Fragment.onCreateOptionsMenu (Menu, MenuInflater) является пустым методом, поэтому вызов super не требуется вообще. Единственной ошибкой здесь была неправильная подпись метода и, возможно, отсутствующий setHasOptionsMenu () в onCreate ()
cmende
6
Замените super.onCreateOptionsMenu на inflater.inflate (R.menu.menu_custom, menu);
Code_Worm
197

У меня была та же проблема, но я думаю, что лучше подвести итог и представить последний шаг, чтобы она заработала:

  1. Добавьте метод setHasOptionsMenu (true) в метод вашего фрагмента onCreate(Bundle savedInstanceState).

  2. Переопределите onCreateOptionsMenu(Menu menu, MenuInflater inflater)(если вы хотите сделать что-то другое в меню вашего Фрагмента) и onOptionsItemSelected(MenuItem item)методы в своем Фрагменте.

  3. Внутри вашего onOptionsItemSelected(MenuItem item)метода Activity убедитесь, что вы возвращаете false, когда действие элемента меню будет реализовано в onOptionsItemSelected(MenuItem item)методе Fragment.

Пример:

Деятельность

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getSupportMenuInflater();
    inflater.inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.activity_menu_item:

            // Do Activity menu item stuff here
            return true;

        case R.id.fragment_menu_item:

            // Not implemented here
            return false;
        default:
            break;
    }

    return false;
}

Фрагмент

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    ....
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // Do something that differs the Activity's menu here
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.activity_menu_item:

            // Not implemented here
            return false;
        case R.id.fragment_menu_item:

            // Do Fragment menu item stuff here
            return true;

        default:
            break;
    }

    return false;
}
Марко ХК
источник
2
Просто не хватало setHasOptionsMenu(true);Спасибо
Чад Бингхам
1
На некоторых устройствах viewPager меню отображается только во второй раз, когда вы переходите к фрагменту
Roel
3
@Marco HC ваш код работает нормально. Но что если я захочу спрятать часть меню «Активность» или «Фрагмент»? У вас есть упоминание о том, где реализовать, какой пункт меню (в деятельности и фрагмент). Но что если я захочу спрятать меню?
Шреяш Махаджан
@iDroidExplorer просто хранит ссылку на этот MenuItem и устанавливает видимость исчезнувшей или невидимой. Это твой вопрос?
Марко ХК
@iDroidExplorer Я попробовал его код и не знаю как, но он автоматически скрывает меню, когда я переключаюсь на другие фрагменты.
Нур Али Батт
156

Если вы обнаружите, что onCreateOptionsMenu(Menu menu, MenuInflater inflater)метод не вызывается, убедитесь, что вы вызываете следующее из onCreate(Bundle savedInstanceState)метода Fragment :

setHasOptionsMenu(true)
Мэтью Блэкфорд
источник
Это дает мне ошибку, как NullPointerException
Pratik Butani
2
Хорошая точка зрения. Я вызывал метод setHasOptionMenu из статического метода newInstance. Поскольку я только прикреплял свой фрагмент, когда saveInstanceState был нулевым, при изменении конфигурации экрана меню не было создано. Метод фрагмента onCreate является правильным местом для установки setHasOptionMenu в значение true.
argenkiwi
1
Я использую Toolbarи должен был звонить setHasOptionsMenu(true)в onCreateView()вместо , onCreate()чтобы сделать это.
КЛО
60

Если вам нужно menuобновить webviewвнутри конкретного Fragment, вы можете использовать:

Фрагмент :

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

    // TODO Add your menu entries here
    inflater.inflate(R.menu.menu, menu);
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.exit:
        System.exit(1);
        break;

    case R.id.refresh:
        webView.reload();
        break;
    }
    return true;

}

menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/exit" android:title="Exit" android:icon="@drawable/ic_action_cancel" />
    <item android:id="@+id/refresh" android:title="Refresh" android:icon="@drawable/ic_action_refresh" />
</menu>
CONvid19
источник
31

TL; DR

Используйте android.support.v7.widget.Toolbarи просто сделайте:

toolbar.inflateMenu(R.menu.my_menu)
toolbar.setOnMenuItemClickListener {
    onOptionsItemSelected(it)
}

Автономная панель инструментов

Большинство из предложенных решений, таких как, setHasOptionsMenu(true)работают только тогда, когда родительская активность имеет панель инструментов в макете и объявляет ее через setSupportActionBar(). Затем Фрагменты могут участвовать в заполнении меню этого точного ActionBar :

Fragment.onCreateOptionsMenu (): инициализировать содержимое стандартного меню параметров узла Fragment.

Если вам нужна отдельная панель инструментов и меню для одного конкретного фрагмента, вы можете сделать следующее:

menu_custom_fragment.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_save"
        android:title="SAVE" />
</menu>

custom_fragment.xml

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

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    ...

CustomFragment.kt

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = inflater.inflate(layout.custom_fragment, container, false)
    val toolbar = view.findViewById<Toolbar>(R.id.toolbar)
    toolbar.inflateMenu(R.menu.menu_custom_fragment)
    toolbar.setOnMenuItemClickListener {
        onOptionsItemSelected(it)
    }
    return view
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.menu_save -> {
            // TODO: User clicked the save button
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Да, это так просто. Вам даже не нужно переопределять onCreate()или onCreateOptionsMenu().

PS: Это работает только с android.support.v4.app.Fragmentи android.support.v7.widget.Toolbar(также обязательно используйте AppCompatActivityи AppCompatтему в вашем styles.xml).

Marius
источник
1
мне очень помогло
Брахми Адигопула
23

В menu.xmlвы должны добавить все пункты меню. Затем вы можете скрыть элементы, которые вы не хотите видеть при начальной загрузке.

menu.xml

<item
    android:id="@+id/action_newItem"
    android:icon="@drawable/action_newItem"
    android:showAsAction="never"
    android:visible="false"
    android:title="@string/action_newItem"/>

Добавьте setHasOptionsMenu(true)метод onCreate () для вызова пунктов меню в вашем классе Fragment.

FragmentClass.java

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

Вам не нужно переопределять onCreateOptionsMenuв вашем классе фрагмента снова. Пункты меню можно изменить (добавить / удалить) с помощью onPrepareOptionsMenuметода переопределения, доступного во фрагменте.

@Override
public void onPrepareOptionsMenu(Menu menu) {
    menu.findItem(R.id.action_newItem).setVisible(true);
    super.onPrepareOptionsMenu(menu);

}
Parinda Rajapaksha
источник
16

Вам нужно использовать menu.clear (), прежде чем раздувать меню.

@Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        menu.clear();
        inflater.inflate(R.menu.menu, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

а также

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }
Spl2nky
источник
1
Это правильно, когда вам нужны разные меню в разных фрагментах, и вы добавляете фрагменты вместо их замены.
Акшай Махаджан,
Спасибо! menu.clear () поможет мне убрать опцию меню Activity.
kimcy929
13

В моем случае вот шаги.

Шаг 1

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Here notify the fragment that it should participate in options menu handling.
    setHasOptionsMenu(true);
}

Шаг 2

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // First clear current all the menu items
    menu.clear();

    // Add the new menu items
    inflater.inflate(R.menu.post_stuff, menu);

    super.onCreateOptionsMenu(menu, inflater);
}

Шаг 3

 @Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.post_stuff:
            Log.d(TAG, "Will post the photo to server");
            return true;
        case R.id.cancel_post:
            Log.d(TAG, "Will cancel post the photo");
            return true;
        default:
            break;
    }
    return super.onOptionsItemSelected(item);
}
Гарри Чжан
источник
У меня уже было меню по основному виду деятельности, используя menu.clear()очищенное предыдущее меню. Работал для меня :)
Anbuselvan Rocky
8

Если вы хотите добавить свое меню на заказ

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_custom, menu);
}
Иезекииль Гарсия
источник
Что если есть вкладка, и вы хотите раздувать разные меню для каждого фрагмента?
Джайнам Джавери
7

У меня была такая же проблема, мои фрагменты были страницами ViewPager. Причина, по которой это происходило, заключается в том, что при создании экземпляра FragmentPagerAdapter я использовал дочерний диспетчер фрагментов, а не диспетчер фрагментов поддержки активности.

farid_z
источник
3

Файл меню:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/play"
        android:titleCondensed="Speak"
        android:showAsAction="always"
        android:title="Speak"
        android:icon="@drawable/ic_play">
    </item>
    <item
        android:id="@+id/pause"
        android:titleCondensed="Stop"
        android:title="Stop"
        android:showAsAction="always"
        android:icon="@drawable/ic_pause">
    </item>
</menu>

Код деятельности:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.speak_menu_history, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.play:
            Toast.makeText(getApplicationContext(), "speaking....", Toast.LENGTH_LONG).show();
            return false;

        case R.id.pause:
            Toast.makeText(getApplicationContext(), "stopping....", Toast.LENGTH_LONG).show();
            return false;

        default:
            break;
    }

    return false;
}

Код фрагмента:

@Override

public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.play:
            text = page.getText().toString();
            speakOut(text);

            // Do Activity menu item stuff here
            return true;

        case R.id.pause:
            speakOf();

            // Not implemented here
            return true;

        default:
            break;
    }
    return false;
}
Суйог Гунджал
источник
3

Ваш код в порядке. Только супер отсутствовал в методе:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // TODO add your menu : 
    inflater.inflate(R.menu.my_menu, menu);
    //TODO call super
    super.onCreateOptionsMenu(menu, inflater);
}
AlexPad
источник
2

Я сходил с ума, потому что ни один из ответов здесь не работал для меня.

Чтобы показать меню мне пришлось позвонить: setSupportActionBar(toolbar)

Выполнено!

Примечание: если ваше toolbarпредставление не в том же макете активности, вы не можете использовать вышеуказанный вызов непосредственно из вашего класса активности, в этом случае вам нужно получить это действие из вашего класса фрагмента, а затем вызвать setSupportActionBar(toolbar). Помните: ваш класс активности должен расширять AppCompatActivity.

Надеюсь, что этот ответ поможет вам.

Филипе Брито
источник
1

Настройка меню параметров после создания фрагмента работала хорошо для меня.

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setHasOptionsMenu(true);        
}
Джерри Фрост
источник
1

Моя проблема была немного другой. Я все сделал правильно. Но я унаследовал неправильный класс для действия, в котором размещен фрагмент.

Таким образом, для ясности, если вы переопределяете onCreateOptionsMenu(Menu menu, MenuInflater inflater)фрагмент, убедитесь, что ваш класс активности, в котором находится этот фрагмент, наследуетandroid.support.v7.app.ActionBarActivity (на случай, если вы захотите поддерживать ниже уровня API 11).

Я унаследовал, android.support.v4.app.FragmentActivityчтобы поддерживать уровень API ниже 11.

Кришна Дипак
источник
1

Я хотел бы добавить одну вещь к этому и причину, по которой она не работает для меня.

Это похоже на ответ Napster.

  1. Убедитесь, что хостинг вашего фрагмента расширяется AppCompatActivity, а не FragmentActivity!

    public class MainActivity extends AppCompatActivity {
    
    }

    Из Справочной документации Google для FragmentActivity:

    Примечание. Если вы хотите реализовать действие, которое включает в себя панель действий, вам следует вместо этого использовать класс ActionBarActivity, который является его подклассом, поэтому он позволяет использовать API-интерфейсы фрагментов на уровне API 7 и выше.

  2. Чтобы обновить ответ Napster - ActionBarActivityтеперь не рекомендуется использовать AppCompatActivityвместо этого.

  3. При использовании AppCompatActivityтакже убедитесь, что вы установили «тему деятельности Theme.AppCompatили аналогичную тему» ​​(Google Doc).

Примечание: android.support.v7.app.AppCompatActivityявляется подклассом android.support.v4.app.FragmentActivityкласса (см. Документацию AppCompatActivity ).

Бастьен
источник
1

В папке вашего меню создайте XML-файл .menu и добавьте этот XML-файл.

<item
    android:id="@+id/action_search"
    android:icon="@android:drawable/ic_menu_search"
    android:title="@string/action_search"
    app:actionViewClass="android.support.v7.widget.SearchView"
    app:showAsAction="always|collapseActionView" />

В вашем фрагменте класса overide этот метод и

implement SearchView.OnQueryTextListener    in your fragment class



@Override
 public void onViewCreated(View view, Bundle savedInstanceState) {    
  super.onViewCreated(view, savedInstanceState);
  setHasOptionsMenu(true);

}

Теперь просто настройте свой XML-файл меню в классе фрагмента.

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_main, menu);

    final MenuItem item = menu.findItem(R.id.action_search);
    final SearchView searchView = (SearchView)    
    MenuItemCompat.getActionView(item);


    MenuItemCompat.setOnActionExpandListener(item,
            new MenuItemCompat.OnActionExpandListener() {
                @Override
                public boolean onMenuItemActionCollapse(MenuItem item) {
                    // Do something when collapsed

                    return true; // Return true to collapse action view
                }

                @Override
                public boolean onMenuItemActionExpand(MenuItem item) {
                    // Do something when expanded
                    return true; // Return true to expand action view
                }
            });

}
павел
источник
0

Если все вышеперечисленное не работает, вам необходимо отладить и убедиться, что была вызвана функция onCreateOptionsMenu (поместив журнал отладки или записи ...)

Если он не запущен, возможно, ваша тема Android не поддерживает панель действий. Откройте AndroidManifest.xml и установите значение для android:themeпанели действий поддержки тем :

 <activity
     android:name=".MainActivity"
     android:label="@string/app_name"
     android:theme="@style/Theme.AppCompat">
Серый волк
источник
0

на вашем OnCreate метод добавления setHasOptionMenu ()

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

Затем переопределите свой onCreateOptionsMenu

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.add("Menu item")
            .setIcon(android.R.drawable.ic_delete)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
Ashana.Jackol
источник