Android - Правильное использование invalidateOptionsMenu()

Я много искал invalidateOptionsMenu(), и я знаю, что он делает. Но я не могу представить ни одного примера реальной жизни, когда этот метод может быть полезен.

Я имею в виду, например, предположим, что мы хотим добавить новый MenuItem в наш ActionBar, мы можем просто получить меню из onCreateOptionsMenu(Menu menu) и использовать его в любом действии кнопки.

Теперь, к моему реальному вопросу, следует единственный способ использования invalidateOptionsMenu()?

bool _OtherMenu;
protected override void OnCreate (Bundle bundle)
{
    _OtherMenu = false;
    base.OnCreate (bundle);
    SetContentView (Resource.Layout.Main);
    Button button = FindViewById<Button> (Resource.Id.myButton);
    button.Click += delegate
    {
        if(_OtherMenu)
            _OtherMenu = false;
        else
            _OtherMenu = true;

        InvalidateOptionsMenu ();
    };
}

public override bool OnCreateOptionsMenu (IMenu menu)
{
    var inflater = this.SupportMenuInflater;
    if(_OtherMenu)
        inflater.Inflate (Resource.Menu.another_menu, menu);
    else
        inflater.Inflate (Resource.Menu.main_activity_menu, menu);

    return base.OnCreateOptionsMenu (menu);
}

Нажмите кнопку и появится другое меню. Нажмите кнопку еще раз, и появится предыдущее меню.

P.S. Извините за синтаксис С#.

Ответы

Ответ 1

invalidateOptionsMenu() используется, чтобы сказать Android, что содержимое меню изменилось, и меню нужно перерисовать. Например, вы нажимаете кнопку, которая добавляет другой элемент меню во время выполнения или скрывает группу элементов. В этом случае вы должны позвонить invalidateOptionsMenu(), чтобы система могла перерисовать его в пользовательском интерфейсе. Этот метод является сигналом для вызова ОС onPrepareOptionsMenu(), где вы выполняете необходимые манипуляции с меню. Кроме того, OnCreateOptionsMenu() вызывается только один раз во время создания активности (фрагмента), поэтому изменения меню времени выполнения не могут быть обработаны с помощью этого метода.

Все можно найти в документации:

После того, как система вызывает onCreateOptionsMenu(), она сохраняет экземпляр из меню, которое вы заполняете, и не будет вызывать onCreateOptionsMenu() снова если по какой-либо причине меню недействительно. Однако вы должны используйте onCreateOptionsMenu() только для создания начального состояния меню и не вносить изменения во время жизненного цикла деятельности.

Если вы хотите изменить меню опций на основе событий, которые происходят во время жизненного цикла деятельности вы можете сделать это в onPrepareOptionsMenu(). Этот метод передает вам объект Menu поскольку он в настоящее время существует, поэтому вы можете его изменить, например, добавить, удалить или отключить элементы. (Фрагменты также предоставляют onPrepareOptionsMenu() Обратный вызов.)

В Android 2.3.x и ниже система вызывает onPrepareOptionsMenu() каждый раз, когда пользователь открывает меню опций (нажимает кнопку "Меню" ).

В Android 3.0 и выше меню опций считается всегда открывается, когда пункты меню представлены в панели действий. Когда событие происходит, и вы хотите выполнить обновление меню, вы должны позвонить invalidateOptionsMenu(), чтобы запросить вызов системы onPrepareOptionsMenu().

Ответ 2

используйте это для перезагрузки нового меню в течение жизненного цикла приложения:

новые:

getActivity().invalidateOptionsMenu();

старый

ActivityCompat.invalidateOptionsMenu(getActivity());

Ответ 3

Вам нужно переопределить метод onPrepareOptionsMenu(), записать код действия для обновления в том же методе, а если вы используете фрагмент, то добавьте setHasOptionsMenu(true); в onCreateView().

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

Ответ 4

Одно из применений, которое я нашел, вызывает порядок операций между onResume и onCreateOptionsMenu/onPrepareOptionsMenu. Естественный порядок (по крайней мере, на платформе 22), кажется, переворачивается, особенно при переориентации вашего устройства.

Вызовите invalidateOptionsMenu() в onResume(), и вы гарантируете, что onPrepareOptionsMenu будет вызываться после onResume (его можно дополнительно вызвать до). Например, это позволит включить элемент меню на основе данных, полученных в onResume.

Ответ 5

Лучший способ, который работал у меня, показан ниже

  • Поместите начальное состояние меню в onCreateOptionsMenu (...)

  • Используйте invalidateOptionsMenu(), чтобы принудительно использовать onCreateOptionsMenu (...) и onPrepareOptionsMenu (...)

  • В onPrepareOptionsMenu (...) вызовите menu.clear(), чтобы удалить все элементы из меню.

  • В режиме onPrepareOptionsMenu (...) поместите ваши динамические изменения меню после очистки

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

Ответ 6

Изменить: Вот лучший ответ на вопрос.

Хорошее использование для invalidateOptionsMenu() - это когда мы имеем ListView и Delete All MenuItem, поэтому, когда ListView пуст, мы должны использовать invalidateOptionsMenu() для удаления Delete All MenuItem.

Вот вопрос, связанный с этим ответом: Question.

Ответ 7

/**
 * Set a hint for whether this fragment menu should be visible.  This
 * is useful if you know that a fragment has been placed in your view
 * hierarchy so that the user can not currently seen it, so any menu items
 * it has should also not be shown.
 *
 * @param menuVisible The default is true, meaning the fragment menu will
 * be shown as usual.  If false, the user will not see the menu.
 */
public void setMenuVisibility(boolean menuVisible) {
    if (mMenuVisible != menuVisible) {
        mMenuVisible = menuVisible;
        if (mHasMenu && isAdded() && !isHidden()) {
            mHost.onSupportInvalidateOptionsMenu();
        }
    }
}

Пример меню XML:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
    android:id="@+id/action_edit"
    android:icon="@drawable/ic_edit"
    android:title="Edit Task"
    app:showAsAction="always" />

<item
    android:id="@+id/action_delete"
    android:icon="@drawable/ic_delete"
    android:title="Delete Task"
    app:showAsAction="always" />

<item
    android:id="@+id/action_check"
    android:icon="@drawable/ic_check"
    android:title="Check Task"
    app:showAsAction="always" />

<item
    android:id="@+id/action_uncheck"
    android:icon="@drawable/ic_undo"
    android:title="Uncheck Task"
    app:showAsAction="always" />
</menu>

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

private boolean isMenuItemChecked;

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    setMenuVisibility(false);
}

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

@Override
public void onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);
    try {
        menu.findItem(R.id.action_check).setVisible(!isMenuItemChecked);
        menu.findItem(R.id.action_uncheck).setVisible(isMenuItemChecked);
    }
    catch(Exception e) {
        Log.e(TAG, "onPrepareOptionsMenu error");
    }
}

public void loadUi(boolean isMenuItemChecked) {
    this.isMenuItemChecked = isMenuItemChecked;
    setMenuVisibility(true);
}

Ответ 8

Это старое, но надеюсь, что это поможет кому-то в будущем.

Одно использование, которое я нашел в сценарии из реальной жизни:

Предположим, у вас есть список элементов, которые хранятся в базе данных, и у вас есть 2 действия:

  1. DisplayActivity: который отображал эти объекты после их получения из базы данных.
  2. EditActivity: используется для редактирования существующего элемента & сохранить это в базу данных.

Вы решили использовать несколько вариантов перехода от DisplayActivity к EditActivity:

  • Сначала: добавить новый элемент в базу данных.
  • Второй: для редактирования существующего элемента.

Чтобы не повторяться, дублируя код, вы решили использовать EditActivity для обеих целей.

И так, вы хотите настроить меню параметров в соответствии с каждой целью. В этом случае вы должны создать меню параметров по умолчанию, используя onCreateOptionsMenu(), и оставить его как есть, когда придет время редактировать существующий элемент; и invalidateOptionsMenu() это когда пришло время создавать новые предметы; и в этом случае onPrepareOptionsMenu() автоматически запускается для настройки вашего меню.

Например, в меню "Параметры" может быть опция удаления для редактирования существующего элемента, и она должна быть скрыта при добавлении нового элемента.

Ответ 9

Из фрагмента звоните getActivity().invalidateOptionsMenu();.