如何更新在ActionBar中显示的菜单项?

96
我有一个Activity,其中包含两个ListFragments。这两个片段都会向菜单贡献菜单项。我设置了一个MenuItem的android:showAsAction属性,以便将其显示为ActionBar上的按钮,它能正常工作。
现在,这个MenuItem的状态是依赖于状态的。它是暂停/恢复队列的菜单选项。我的问题是我无法弄清楚如何在创建Fragment时设置其初始状态。
它的状态取决于队列是否被暂停。因此,我有一个AsyncTask来获取队列,并根据队列的状态设置一个布尔值(pause)。我调用onPrepareOptionsMenu来基于队列的上一个已知状态设置暂停菜单项的文本,如果我将MenuItem保留在实际菜单中,这样做非常有效。您点击菜单图标,onPrepareOptionsMenu被触发并在显示菜单之前更新菜单。
问题是,如果我将同一MenuItem放在ActionBar上(显示为操作按钮),我如何强制它更新而不必调用onPrepareOptionsMenu?我需要能够这样做,因为在第一次启动应用程序时,我发送请求以获取队列,但任务返回后ActionBar已经配置和显示。在我的片段中,我创建了一个处理程序,每次我获得队列更新时都会被调用,但我该怎么更新ActionBar上MenuItem的文本呢?除了onPrepareOptionMenu,我似乎找不到其他方法来获取当前设置的菜单以操纵它。
6个回答

179

选项#1:尝试invalidateOptionsMenu()。我不知道这是否会立即重绘操作栏。

选项#2:检查对应的MenuItem是否有返回值,通过调用getActionView()方法。可能showAsAction只是自动为您创建操作视图。如果是这样,您可以启用/禁用该View

我似乎找不到一种方法来获取当前设置的菜单以进行操作,除了在onPrepareOptionMenu中。

您可以在onCreateOptionsMenu()中获得被传递给您的Menu对象。引用文档

您可以安全地保存菜单(和从菜单创建的任何项),并按需要进行修改,直到下次调用onCreateOptionsMenu()时。


2
尝试了选项#1,这解决了问题。由于我试图在来自单独线程的回调中更新UI,因此它会抛出异常,因为我实际上不在UI线程上。为了解决这个问题,我创建了一个Handler,并在调用我的回调时向Handler发送了一个刷新消息。但最终我使用getActivity().invalidateOptionsMenu()来刷新菜单。 - brockoli
@brockoli:啊,太好了!鉴于该方法的Javadocs措辞,我对其是否能产生预期效果持怀疑态度,尽管似乎这是他们在首次添加到API Level 11时的原因。很高兴听到它对你有用! - CommonsWare
从片段调用刷新项目,但此后点击侦听器未被调用。 - Vasil Valchev
7
如果您正在使用支持库,请改用supportInvalidateOptionsMenu()而不是其他方法。 - Tim Kist
2
@TimKist,supportInvalidateOptionsMenu()现在已经过时了,你可以安全地使用invalidateOptionsMenu() - c0dehunter
显示剩余3条评论

14
在我的情况下:invalidateOptionsMenu 只是将文本重置为原始文本,但是直接访问菜单项并重写所需文本可以正常工作:

在我的情况下: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;
}

你是如何通过 mnuTopMenuActionBar_ 获取 ActionBar 视图的句柄的? - Unpossible
1
当操作栏被初始化时,我将视图保存到成员变量中...就像这样:@Override public boolean onCreateOptionsMenu(Menu menu) {MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.magazine_swipe_activity, menu); mnuTopMenuActionBar_ = menu; return true;} - cV2
通过这样做,你可能会遇到同步问题吧?我的意思是,你不知道onCreateOptionMenu究竟何时运行,因此你可能会在mnuTopMenuActionBar_未初始化的情况下达到你的代码块,对吧?你会如何解决这个问题呢? - acrespo
嘿,如果使用ActionBar(是的,在这里)则始终调用此方法,因此没有问题...(直接在活动开始时) - cV2

13

要从碎片(Fragment)中刷新菜单,只需调用:

getActivity().invalidateOptionsMenu();

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

如果你想要在Android应用中添加选项菜单,可以使用OnPrepareOptionsMenu方法。你可以在这里找到相关内容here


4
MenuInflater的目的是什么? - IgorGanapolsky
这太棒了。 - Steve Kamau

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的引用,然后在稍后的某个时间点更改其状态(例如更改图标状态)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接