如何在操作栏中隐藏菜单项?

374

我有一个带有菜单项的操作栏。如何隐藏/显示该菜单项?

这是我想要做的:

MenuItem item = (MenuItem) findViewById(R.id.addAction);
item.setVisible(false);
this.invalidateOptionsMenu();
27个回答

527
获取指向该项的MenuItem,调用其setVisible方法以调整其可见性,然后在您的活动上调用invalidateOptionsMenu(),以便ActionBar菜单相应地进行调整。
更新: MenuItem不是您布局中的常规视图。它是一种特殊的、完全不同的东西。代码返回null作为item,这会导致崩溃。您需要做的是:
MenuItem item = menu.findItem(R.id.addAction);

以下是调用的顺序: 首先调用invalidateOptionsMenu(),然后在onCreateOptionsMenu(Menu)中获取MenuItem的引用(通过调用menu.findItem()),并在其上调用setVisible()


1
这是我最初想到的,但会导致应用程序崩溃。 - Stir Zoltán
3
@Stir Zoltán:如果应用程序崩溃,那么你可能做错了。比如说,你可能使用了getItem而不是findItem,导致MenuItemnull。除非我们看到你的代码和崩溃日志,否则我们永远不会知道确切原因。请注意检查代码。 - K-ballo
7
@Stir Zoltán:我认为你最后的评论毫无意义...只需在onCreateOptionsMenu中获取菜单项的引用,并在那时设置该项的可见性。或者在决定是否可见之前一直保留该引用。 - K-ballo
39
我认为这个答案(在最好情况下)措辞不当,因为步骤的顺序是错误的。 正确的顺序是首先调用invalidateOptionsMenu(),然后在onCreateOptionsMenu(Menu)内获取对MenuItem的引用(通过调用menu.findItem())并在其上调用setVisible()suhas_smP1r4nh4的答案提供了正确的方法。 - Ted Hopp
如果在此之后调用了 setTitle(),则菜单将再次出现。因此,我认为 https://dev59.com/UWgv5IYBdhLWcg3wTvLL#13099201 是最佳答案。 - lalthomas
显示剩余8条评论

183
发现这个问题的补充说明:
如果您想在运行时更改菜单项的可见性,只需在活动中设置一个成员变量来记住您要隐藏菜单,并调用invalidateOptionsMenu(),并在重写的onCreateOptionsMenu(...)方法中隐藏这些项目。
//anywhere in your code
...
mState = HIDE_MENU; // setting state
invalidateOptionsMenu(); // now onCreateOptionsMenu(...) is called again
...

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
    // inflate menu from xml
    MenuInflater inflater = getSupportMenuInflater();
    inflater.inflate(R.menu.settings, menu);

    if (mState == HIDE_MENU)
    {
        for (int i = 0; i < menu.size(); i++)
            menu.getItem(i).setVisible(false);
    }
}

在我的例子中,我已经隐藏了所有的项目。

2
这正是我一直在寻找的。持有 MenuItem 并调用 setVisible() 似乎没有达到我预期的效果(可能是因为我在调用 invalidateOptionsMenu() 后重建了菜单),但无论如何,这正是我所希望的,谢谢! - Matt
4
如果你要隐藏每个项目,有一种更简单的方法。不需要循环遍历每个项目,只需使用以下代码:if (HIDE_MENU) { return false; } else { getSupportMenuInflater().inflate(R.menu.menu_settings, menu); return true; } 文档说明:“必须返回 true 才能显示菜单;如果返回 false,则不会显示”。 - w3bshark
另外,我想提一下,这种方法比被接受的答案更加简洁。感谢分享! - w3bshark
通过调用invalidateOptionMenu(),onCreateOptionMenu()被调用并且我在onCreateOptionMenu()中处理我的条件。感谢您提供的优秀答案。 - user1912026
1
onPrepareOptionsMenu() 应该用于显示/隐藏逻辑,而不是 onCreateOptionsMenu(),因为后者仅调用一次,因此如果要在初始化后更改菜单项,则没有用处。 因此,在 onCreate 中填充,但在 onPrepare 中显示/隐藏。 - JCutting8

96

可以。

  1. 您可以设置标志/条件。
  2. 当您想隐藏选项时,请调用invalidateOptionsMenu()。 这将调用onCreateOptionsMenu()
  3. onCreateOptionsMenu()中,检查标志/条件并以以下方式显示或隐藏:
MenuItem item = menu.findItem(R.id.menu_Done);

if (flag/condition)) {
  item.setVisible(false); 
} else { }

2
еә”иҜҘжҳҜ invalidateOptionsMenu иҖҢдёҚжҳҜ invalidateOptions еҗ—пјҹ - razz
3
如果您将标志设置为布尔类型,只需根据需要将项目的可见性设置为标志(或!标志)。 因此,item.setVisbility(!flag); 可以使此代码成为一行,无需if条件。 - jwehrle
变量 "menu" 是在哪里定义的? - Jono
它作为参数传递给onCreateOptionsMenu函数。 - suhas_sm
使用这种方法将意味着该项仍然占用空间,您可能会在UI中出现一个“间隙”,其中应该放置按钮。在onPrepareOptionsMenu()中使用removeItem就可以解决问题。 - JCutting8

45

我希望能够获得更多背景信息的答案。现在我已经弄清楚了,我将添加那个答案。

在菜单xml中默认隐藏按钮

默认情况下,分享按钮将被隐藏,由android:visible="false"设置。

enter image description here

main_menu.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">

    <!-- hide share button by default -->
    <item
        android:id="@+id/menu_action_share"
        android:icon="@drawable/ic_share_white_24dp"
        android:visible="false"     
        android:title="Share"
        app:showAsAction="always"/>

    <item
        android:id="@+id/menu_action_settings"
        android:icon="@drawable/ic_settings_white_24dp"
        android:title="Setting"
        app:showAsAction="ifRoom"/>

</menu>

在代码中显示按钮

但是共享按钮可以根据一些条件选择性地显示。

在此输入图片描述

MainActivity.java

public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_menu, menu);
    MenuItem shareItem = menu.findItem(R.id.menu_action_share);

    // show the button when some condition is true
    if (someCondition) {        
        shareItem.setVisible(true);
    }

    return true;
}

另请参阅


1
应该使用onPrepareOptionsMenu()来处理显示/隐藏逻辑,而不是使用onCreateOptionsMenu(),因为后者只会被调用一次,如果想要在初始化后更改菜单项,则无用。因此,在onCreate中进行填充,但在onPrepare中进行显示/隐藏,然后使用invalidateOptionsMenu()刷新菜单。 - JCutting8

40

您可以这样调用:

MenuItem item = menu.findItem(R.id.my_item);
item.setVisible(false);

更新:

确保你的代码不会返回 null 作为 item,否则可能会导致应用程序崩溃。


使用这种方法将意味着该项仍然占用空间,您可能会在UI中出现按钮应该存在的“间隙”。在onPrepareOptionsMenu()中使用removeItem就可以解决问题。 - JCutting8

24

对我来说不起作用。 我必须明确使用onPrepareOptionsMenu将项目设置为不可见。

因此,请使用onCreateOptionsMenu创建菜单,使用onPrepareOptionsMenu更改可见性等。


1
对我来说两种方式都可以工作,但根据Android文档onPrepareOptionsMenu似乎是执行此类型操作的正确位置:“准备显示屏幕的标准选项菜单。每次显示菜单时都会调用此方法。您可以使用此方法有效地启用/禁用项目或以其他方式动态修改内容。” - yuval
是的,这是理想的情况。应该使用onPrepareOptionsMenu()进行显示/隐藏逻辑,而不是使用onCreateOptionsMenu(),因为它只被调用一次,所以如果您想在初始化后更改菜单项,则无用。因此,在onCreate中填充,但在onPrepare中显示/隐藏,然后使用invalidateOptionsMenu()刷新菜单。 - JCutting8

11

在菜单布局文件中,最初将菜单项的可见性设置为false,如下所示:

<?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:visible="false"
        android:id="@+id/action_do_something"
        android:title="@string/txt_do_something"
        app:showAsAction="always|withText"
        android:icon="@drawable/ic_done"/>
</menu>

在填充菜单后,在您的onCreateOptionsMenu()中将菜单项的可见性设置为false即可。

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    inflater.inflate(menu,R.menu.menu);
    MenuItem item = menu.findItem(R.id.menuItemId);
    if (item != null){
        item.setVisible(false);
    }
}

onCreateOptionsMenu方法不返回布尔值。但是解决方案完美地解决了问题。 - Joseph

10

试一下这个:

MenuItem myitem = menu.findItem(R.id.my_item);
myitem.setVisible(false);

8
这个对我来说在Activity和Fragment中都起作用。
@Override
public void onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);
    if (menu.findItem(R.id.action_messages) != null)
        menu.findItem(R.id.action_messages).setVisible(false);
}

1
在我的情况下,onPrepareOptionsMenu 返回的是布尔值,而不是 void。 - CoolMind

7

根据Android开发者官方网站,OnCreateOptionMenu(Menu menu) 不建议在运行时更改菜单项或图标可见性等。

系统调用onCreateOptionsMenu() 后,会保留您填充的Menu实例,并且除非因某种原因使菜单无效,否则不会再次调用onCreateOptionsMenu()。 但是,您应该仅在创建初始菜单状态时使用onCreateOptionsMenu(),而不是在活动生命周期期间进行更改。

如果要根据活动生命周期中发生的事件修改选项菜单,则可以在onPrepareOptionsMenu()方法中执行此操作。 此方法将当前的Menu对象传递给您,因此您可以修改它,例如添加,删除或禁用项目。(片段还提供了onPrepareOptionsMenu()回调。)--Android Developer官方网站--

推荐使用onOptionsItemSelected(MenuItem item)方法来跟踪用户输入。

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    int id = item.getItemId();

    if (id == R.id.edit) {
        Intent intent = new Intent(this, ExampleActivity.class);
        intent.putExtra(BUNDLE_KEY, mConnection);
        startActivityForResult(intent, PICK_CHANGE_REQUEST);
        return true;
    } else if (id == R.id.delete) {
        showDialog(this);
        return true;
    }

    return super.onOptionsItemSelected(item);
}

如果您需要在运行时更改菜单项,您可以使用onPrepareOptionsMenu(Menu menu)来更改它们。
@Override
public boolean onPrepareOptionsMenu(Menu menu){

    if (Utils.checkNetworkStatus(ExampleActivity.this)) {
        menu.findItem(R.id.edit).setVisible(true);
        menu.findItem(R.id.delete).setVisible(true);
    }else {
        menu.findItem(R.id.edit).setVisible(false);
        menu.findItem(R.id.delete).setVisible(false);
    }
    return true;
} 

一些项目始终可见,因此当我对始终可见的项目使用 setVisible(false) 时,它不会消失,直到我点击三个点(菜单本身)。如果我在 onPrepareOptionsMenu 中使用 invalidateOptionsMenu(),则项目会立即重新组织,但它们会失去其操作(如果我单击任何项目,则不会执行任何操作)。 - Aliton Oliveira

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