Як додати меню "Параметри" до "Фрагмент" в Android


399

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

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

Java:

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здається, не працює.


можливо, дурне питання ... ти правильно натискаєш кнопку меню?
Овідіу Латку

2
..lol ... так, я натиснув кнопку меню, я також спробував це з і без: fav.setShowAsAction (MenuItem.SHOW_AS_ACTION_ALWAYS);
misterbassman

Привіт, можливо, ця тема допоможе тобі або перевірить демонстрацію api на робочий приклад.
kameny

Відповіді:


604

Викличте супер метод:

Java:

    @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; і тепер все працює
misterbassman

183
не дзвонив setHasOptionsMenu (правда) у фрагменті onCreate вже зараз
удвох

7
Я передавав свою діяльність на фрагмент і стикався з цією проблемою. Підпис методу змінився від public boolean до public void, а також мінялися аргументи. Обов’язково врахуйте це!
you786

14
Зауважте, що Fragment.onCreateOptionsMenu (Меню, MenuInflater) - це порожній метод, тому виклик супер взагалі не потрібно. Єдиною помилкою тут був неправильний підпис методу та, можливо, відсутній набірHasOptionsMenu () у onCreate ()
cmende

6
Замініть super.onCreateOptionsMenu на inflater.inflate (R.menu.menu_custom, меню);
Code_Worm

197

У мене була така ж проблема, але я думаю, що краще підвести підсумки та запровадити останній крок, щоб він працював:

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

  2. Замініть onCreateOptionsMenu(Menu menu, MenuInflater inflater)(якщо ви хочете зробити щось інше в меню свого фрагмента) та onOptionsItemSelected(MenuItem item)методи у своєму фрагменті.

  3. Всередині onOptionsItemSelected(MenuItem item)методу вашої активності переконайтеся, що ви повернули помилкове значення, коли дія пункту меню буде реалізовано в onOptionsItemSelected(MenuItem item)методі фрагмента.

Приклад:

Діяльність

@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)методом фрагмента :

setHasOptionsMenu(true)

Це дає мені помилку, як NullPointerException
Pratik Butani

2
Гарна думка. Я викликав метод setHasOptionMenu зі статичного методу newInstance. Оскільки я вкладав фрагмент лише тоді, коли SaveInstanceState був недійсним, коли конфігурація екрана змінила меню, воно не буде створене. Метод onCreate фрагмента - це правильне місце, де встановити setHasOptionMenu на істинне.
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>

31

TL; DR

Використовуйте android.support.v7.widget.Toolbarта просто робіть:

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

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

Більшість запропонованих рішень, як-от, setHasOptionsMenu(true)працюють лише тоді, коли батьківська діяльність має панель інструментів у своєму макеті та оголошує її через setSupportActionBar(). Тоді фрагменти можуть брати участь у меню цієї точної ActionBar :

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

Якщо ви хочете окрему панель інструментів і меню для одного конкретного фрагмента, ви можете зробити наступне:

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


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 (), щоб викликати елементи меню у вашому класі фрагментів.

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

}

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

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()очищене попереднє меню. Працював для мене :)
Анбусельван Рокі,

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.


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

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(у випадку, якщо ви хочете підтримати нижче рівня 11 API).

Я успадковував рівень android.support.v4.app.FragmentActivityпідтримки API нижче 11.


1

Я хотів би додати до цього і те, що це не працювало для мене.

Це схоже на відповідь Напстера.

  1. Переконайтеся, що хостинг вашого фрагмента розширюється AppCompatActivity, ні FragmentActivity!

    public class MainActivity extends AppCompatActivity {
    
    }

    З Довідкової документації Google для FragmentActivity:

    Примітка. Якщо ви хочете реалізувати діяльність, що включає в себе панель дій, слід замість цього використовувати клас ActionBarActivity, який є підкласом цього класу, тому дозволяє використовувати API фрагментів на рівні 7 і вище API.

  2. Щоб оновити відповідь Напстера - ActionBarActivityтепер застаріла, AppCompatActivityзамість цього використовуйте .

  3. Під час використання AppCompatActivityтакож переконайтеся, що ви встановили "тему діяльності на Theme.AppCompatподібну тему" (Google Doc).

Примітка: android.support.v7.app.AppCompatActivityє підкласом android.support.v4.app.FragmentActivityкласу (див. Refc док. AppCompatActivity ).


1

У папці меню створіть файл .menu xml та додайте цей 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" />

У вашому класі фрагмента перекладіть цей метод і

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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.