如何在Android上更改选项菜单中的MenuItem?

45

我在我的Activity上有一个选项菜单,其中有一个名为“启动”的MenuItem。当选择此MenuItem时,我希望更改菜单,使其包含一个名为“停止”的MenuItem。最后,当选择“停止”时,我希望再次更改回“启动”。

这是部分代码,它没有起作用。我在mymenu.xml中列出了“启动”和“停止”,在创建菜单时应该将“停止”删除:

public class MyActivity extends Activity {
    private boolean isStarted = false;

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.start:
            isStarted = true;
            return true;
        case R.id.stop:
            isStarted = false;
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if(isStarted) {
            menu.removeItem(R.id.start);
            menu.add(R.id.stop);
        } else {
            menu.removeItem(R.id.stop);
            menu.add(R.id.start);
        }
        return true;
    }
}

1
你已经尝试过在菜单创建时删除Stop了吗?代码看起来不错。除此之外,我没有发现任何可能引起问题的地方。 - Octavian Helm
@Octavian:我在getMenuInflater();后尝试使用menu.removeItem(R.id.stop);,但它没有起作用。我要么得到两个菜单项,一个是“start”,另一个是“false”(应该是“stop”),要么当我应该显示菜单时,菜单崩溃了。 - Jonas
1
你是在哪里尝试调用 removeItem()?是在 onPrepareOptionsMenu() 中吗? - Octavian Helm
@Octavian:我在onCreateOptionsMenu()中首次移除了“stop”项目,然后在onPrepareOptionsMenu()中修改了项目。我现在已将此代码添加到问题中。 - Jonas
6个回答

100

对于这种操作,我通常选择不改变菜单项,而是隐藏您不需要的那些项:

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);
    menu.findItem(R.id.start).setVisible(!isStarted);
    menu.findItem(R.id.stop).setVisible(isStarted);
    return true;
}

1
刚刚看到我忘记调用之前建议并在文档源代码中指定的超类了。 - Flygenring
只是为了更新一下,源代码可以在http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3_r1/android/app/Activity.java?av=f#2272找到。 - Flygenring

21

Flygenring的答案是正确的,但是menu.findItem()很慢,在onPrepareOptionsMenu(Menu menu)中调用它会导致不好的用户体验。最好在创建菜单时获取MenuItem对象,然后每次菜单出现在屏幕上时只调用setVisible:

    MenuItem mDynamicMenuItem;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        // Get dynamic menu item
        mDynamicMenuItem = menu.findItem(R.id.menu_item);
        return true;
    }

    // Prepare the Screen's standard options menu to be displayed. This is called right 
    // before the menu is shown, every time it is shown. You can use this method to
    // efficiently enable/disable items or otherwise dynamically modify the contents.
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);
        // Here is just a good place to update item
        mDynamicMenuItem.setVisible(isVisible);
        return true;
    }

当菜单中只有一个项目时,此方法无效。 - João Carlos

6
在您完成更改后,可能需要调用super.onPrepareOptionsMenu。根据文档

派生类应始终调用基类实现。


3
我已经找到了解决方案。在调用removeItem()时,你实际上是在删除MenuItem,因此也删除了引用。使用这段代码可以解决问题。
private boolean isStarted = false;

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case 1:
        isStarted = true;
        return true;
    case 0:
        isStarted = false;
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}

@Override
public boolean onPrepareOptionsMenu(Menu menu) {

    if(isStarted) {
        menu.removeItem(1);
        menu.add(0, 0, 0, "Stop");
    } else {
        menu.removeItem(0);
        menu.add(0, 1, 0, "Start");
    }

    return super.onPrepareOptionsMenu(menu);
}

您需要重新创建MenuItem。这也是false标签的原因。实际上,您不需要MenuInflater,因为您通过代码创建Menu,所以也不需要任何菜单XML文件。

1
感谢这篇文章中的信息,解决了我菜单中错误标签的问题。我确实需要稍微修改它,并且最终的代码如下,希望能节省其他人的时间和挫败感。这是一个略有不同的解决方案,但我所做的主要更改是将.setVisible设置为True或False,除此之外,i.shadrins的解决方案最适合我的需求。
    @Override
public boolean onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);

    if(loggedIn) 
    {
        logIn.setVisible(false);
        logOut.setVisible(true);
    } 
    else 
    {
        logIn.setVisible(true);
        logOut.setVisible(false);
    }
    return true;
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    logIn = menu.findItem(R.id.loggedOut);
    logOut = menu.findItem(R.id.loggedIn);
    return true;
}

应该把它放在哪个文件中? - NoWar

0
在 Android 3.0 及更高版本中,您应该调用 invalidateOptionsMenu() 来请求系统调用 onPrepareOptionsMenu()。然后您可以在该方法中修改选项菜单。您可以查看 Android 文档中的在运行时更改菜单项部分,了解更多详细信息 https://developer.android.com/guide/topics/ui/menus#options-menu

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