Как обновить пункт меню, отображаемый в ActionBar?

94

У меня есть Activity с 2 фрагментами. Оба являются ListFragments, и оба вносят MenuItems в Menu. У меня есть один MenuItem, для которого я установил атрибут android: showAsAction, чтобы он отображался как кнопка на ActionBar. Что отлично работает.

Теперь MenuItem зависит от состояния. Это пункт меню «Пауза / Возобновить» для приостановки и возобновления очереди. Моя проблема в том, что я не могу понять, как установить начальную статую при создании фрагмента.

Его состояние зависит от того, приостановлена ​​очередь или нет. Итак, у меня есть AsyncTask, который получает очередь и устанавливает логическое значение (приостановлено) в зависимости от состояния очереди. Я вызываю onPrepareOptionsMenu, чтобы установить текст для пункта меню «Пауза» на основе последнего известного состояния очереди, и это отлично работает, если я оставлю MenuItem в фактическом меню. Вы касаетесь значка меню, и onPrepareOptionsMenu запускается, и меню обновляется перед отображением.

Проблема в том, что если я помещу тот же самый MenuItem в ActionBar (showAsAction), как я могу заставить его обновиться без вызова onPrepareOptionsMenu? Мне нужно иметь возможность сделать это, потому что при первом запуске приложения я отправляю запрос на получение очереди, но задача возвращается после того, как ActionBar настроен и отображается. Я создал обработчик в своем фрагменте, который вызывается каждый раз, когда я получаю обновление очереди, но оттуда, как я могу обновить текст для моего MenuItem в ActionBar? Кажется, я не могу найти способ получить текущее установленное меню для управления им, за исключением onPrepareOptionMenu.

Роб В.

брокколи
источник

Ответы:

175

Вариант №1: Попробуйте invalidateOptionsMenu(). Я не знаю, приведет ли это к немедленной перерисовке панели действий или нет.

Вариант № 2: Посмотрите, getActionView()вернет ли что-нибудь для пострадавших MenuItem. Возможно, что showAsActionпросто автоматически создаст для вас виды действий. Если это так, вы, вероятно, можете включить / отключить это View.

Кажется, я не могу найти способ получить текущее установленное меню для управления им, за исключением onPrepareOptionMenu.

Вы можете повесить на Menuпредмет, который вам передали onCreateOptionsMenu(). Цитата из документов :

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

CommonsWare
источник
2
Пробовал вариант №1, и это помогло. Поскольку я пытался обновить пользовательский интерфейс в обратном вызове из отдельного потока, он генерировал исключение, поскольку на самом деле я не был в потоке пользовательского интерфейса. Чтобы исправить это, я создал обработчик и отправил ему сообщение об обновлении, когда был вызван мой обратный вызов. Но в конечном итоге я использовал getActivity (). InvalidateOptionsMenu (), чтобы обновить меню.
brockoli
@brockoli: Ах, хорошо! Учитывая формулировку документации Javadocs для этого метода, я скептически относился к тому, что он будет иметь желаемый эффект, хотя, похоже, это была причина, по которой они изначально добавили его в API уровня 11. Рад слышать, что это работает на вас!
CommonsWare
Я бился головой о стену, пытаясь понять это, и это работает как шарм!
MinceMan
7
Если вы используете библиотеку поддержки, используйте supportInvalidateOptionsMenu()вместо
нее
2
@TimKist supportInvalidateOptionsMenu()устарел; можно смело пользоваться invalidateOptionsMenu().
Primož Kralj
12

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

if (mnuTopMenuActionBar_ != null) {
    MenuItem mnuPageIndex = mnuTopMenuActionBar_
        .findItem(R.id.menu_magazin_pageOfPage_text);

    if (mnuPageIndex != null) {
        if (getScreenOrientation() == 1) {
            mnuPageIndex.setTitle((i + 1) + " von " + pages);
        }
        else {
            mnuPageIndex.setTitle(
                (i + 1) + " + " + (i + 2) + " " + " von " + pages);
        }
        // invalidateOptionsMenu();
    }
}

из-за комментария ниже я смог получить доступ к пункту меню с помощью следующего кода:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.magazine_swipe_activity, menu);
    mnuTopMenuActionBar_ = menu;
    return true;
}
cV2
источник
Как вы получили доступ к представлению ActionBar mnuTopMenuActionBar_?
Пол Меннега
1
когда панель действий инициализируется, я сохранил представление в переменной-члене ... вот так: @Override public boolean onCreateOptionsMenu (меню меню) {MenuInflater inflater = getMenuInflater (); inflater.inflate (R.menu.magazine_swipe_activity, меню); mnuTopMenuActionBar_ = меню; вернуть истину; }
cV2 04
Делая это, у вас могут возникнуть проблемы с синхронизацией, верно? Я имею в виду. вы не знаете ТОЧНО, когда будет запускаться onCreateOptionMenu, поэтому вы можете добраться до своего фрагмента кода mnuTopMenuActionBar_неинициализированным, верно? Как бы вы с этим справились?
площадь
эй, если используется панель действий (да, вот она), этот метод всегда вызывается, поэтому с этим нет проблем ... (непосредственно при запуске активности) stackoverflow.com/questions/7705927/…
cV2
11

Чтобы обновить меню из фрагмента, просто вызовите:

getActivity().invalidateOptionsMenu();
CoolMind
источник
4

Я использовал этот код:

public boolean onPrepareOptionsMenu (Menu menu) {       
    MenuInflater inflater = getMenuInflater();
    TextView title  = (TextView) findViewById(R.id.title);
    menu.getItem(0).setTitle(
        getString(R.string.payFor) + " " + title.getText().toString());
    menu.getItem(1).setTitle(getString(R.string.payFor) + "...");
    return true;        
}

И мне понравилось, вы можете найти OnPrepareOptionsMenu здесь

ПРОСИТЬ
источник
4
Какова здесь цель MenuInflater?
Игорь Ганапольский
Это великолепно
Стив Камау
2

Сначала выполните две строки кода, чтобы обновить элементы панели действий, прежде чем вы должны установить условие в oncreateOptionMenu (). Например:

Boolean mISQuizItemSelected = false;

/**
 * Called to inflate the action bar menus
 *
 * @param menu
 *      the menu
 *
 * @return true, if successful
 */

@Override
public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu items for use in the action bar

    inflater.inflate(R.menu.menu_demo, menu);

    //condition to hide the menus
    if (mISQuizItemSelected) {
        for (int i = 0; i < menu.size(); i++) {
            menu.getItem(i).setVisible(false);
        }
    }

    return super.onCreateOptionsMenu(menu);
}

/**
 * Called when the item on the action bar being selected.
 *
 * @param item
 *      menuitem being selected
 *
 * @return true if the menuitem id being selected is matched
 * false if none of the menuitems id are matched
 */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getId() == R.id.action_quiz) {
        //to navigate based on the usertype either learner or leo
        mISQuizItemSelected = true;

        ActionBar actionBar = getActionBar();
        invalidateOptionMenu();
    }
}
саранья
источник
1

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

private MenuItem menuItem_;

@Override
public boolean onCreateOptionsMenu(Menu menuF) 
{
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_layout, menuF);
    menuItem_ = menuF.findItem(R.id.menu_item_identifier);
    return true;
}

В этом случае вы удерживаете ссылку MenuItem в начале, а затем меняете ее состояние (например, для изменения состояния значка) в более поздний заданный момент времени.

Джей Снайдер
источник
-1

В Kotlin 1.2 просто позвоните:

invalidateOptionsMenu()

и onCreateOptionsMenuфункция будет вызвана снова.

j_gonfer
источник