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

Posted

技术标签:

【中文标题】如何更改 Android 上选项菜单上的 MenuItem?【英文标题】:How can I alter a MenuItem on the Options Menu on Android? 【发布时间】:2011-05-11 03:05:48 【问题描述】:

我的Activity 上有一个带有MenuItem“开始”的选项菜单。 When this MenuItem is selected I would like to alter the Menu so it contains a MenuItem "Stop".最后选择“停止”时,我想改变回“开始”。

这是我的部分代码不起作用。我在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;
    

【问题讨论】:

您是否已经尝试在创建菜单时删除停止?代码看起来不错。我找不到任何会导致其他问题的东西。 @Octavian:我在getMenuInflater(); 之后尝试了menu.removeItem(R.id.stop);,但没有成功。我要么得到两个菜单项,一个“开始”,一个“假”(应该是“停止”),或者当我应该显示时菜单崩溃。 你想在哪里打电话给removeItem()?在onPrepareOptionsMenu()? @Octavian:我第一次删除了onCreateOptionsMenu() 中的“停止”项目,然后我更改了onPrepareOptionsMenu() 中的项目。我现在将此添加到问题中的代码中。 【参考方案1】:

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

【讨论】:

【参考方案2】:

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;
    

【讨论】:

此方法在菜单中只有一项时不起作用。【参考方案3】:

感谢这篇文章中的信息,因为它解决了我菜单中错误标签的问题。我确实不得不稍微修改它并让最终代码运行良好,希望它可以为其他人节省一些时间和挫败感。它的解决方案略有不同,但我所做的主要更改是将 .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;

【讨论】:

应该放在哪个文件中?【参考方案4】:

对于这种类型的操作,我通常选择不改变菜单项,而只是隐藏你不需要的:

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

【讨论】:

刚刚看到我忘记按照前面的建议调用超类,并在docs 和source 中指定 只是为了更新,源代码可以在grepcode.com/file/repository.grepcode.com/java/ext/…找到【参考方案5】:

我得到了解决方案。调用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 文件。

【讨论】:

【参考方案6】:

您可能需要在完成更改后调用 super.onPrepareOptionsMenu。来自docs:

派生类应该总是调用 一直到基类 实施。

【讨论】:

以上是关于如何更改 Android 上选项菜单上的 MenuItem?的主要内容,如果未能解决你的问题,请参考以下文章

菜单(Menu)的三中创建方式——Android开发之路2

如何更改 Android 选项菜单的背景?

如何更改选项菜单的背景颜色?

android中的菜单menu可以在屏幕上一直显示吗

android:以编程方式更改选项菜单项

Android详解Android的menu菜单