【问题标题】:Android: How to enable/disable option menu item on button click?Android:如何在按钮单击时启用/禁用选项菜单项?
【发布时间】:2026-02-20 02:00:02
【问题描述】:

当我使用onCreateOptionsMenuonOptionsItemSelected 方法时,我可以轻松做到这一点。

但我在屏幕某处有一个按钮,单击该按钮时,它应该启用/禁用上下文菜单项。

【问题讨论】:

    标签: android contextmenu menuitem


    【解决方案1】:

    我所做的是在onCreateOptionsMenu 保存对菜单的引用。这类似于 nir 的答案,除了我没有保存每个单独的项目,而是保存了整个菜单。

    声明一个菜单Menu toolbarMenu;

    然后在onCreateOptionsMenu将菜单保存到您的变量中

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        toolbarMenu = menu;
        return true;
    }
    

    现在您可以随时访问您的菜单及其所有项目。 toolbarMenu.getItem(0).setEnabled(false);

    【讨论】:

      【解决方案2】:

      一个老问题的更现代的答案:

      MainActivity.kt

      private var myMenuIconEnabled by Delegates.observable(true) { _, old, new ->
          if (new != old) invalidateOptionsMenu()
      }
      
      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)
      
          findViewById<Button>(R.id.my_button).setOnClickListener { myMenuIconEnabled = false }
      }
      
      override fun onCreateOptionsMenu(menu: Menu?): Boolean {
          menuInflater.inflate(R.menu.menu_main_activity, menu)
          return super.onCreateOptionsMenu(menu)
      }
      
      override fun onPrepareOptionsMenu(menu: Menu): Boolean {
          menu.findItem(R.id.action_my_action).isEnabled = myMenuIconEnabled
          return super.onPrepareOptionsMenu(menu)
      }
      

      menu_main_activity.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">
      <item
          android:id="@+id/action_my_action"
          android:icon="@drawable/ic_my_icon_24dp"
          app:iconTint="@drawable/menu_item_icon_selector"
          android:title="My title"
          app:showAsAction="always" />
      </menu>
      

      menu_item_icon_selector.xml

      <?xml version="1.0" encoding="utf-8"?>
      <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:color="?enabledMenuIconColor" android:state_enabled="true" />
      <item android:color="?disabledMenuIconColor" />
      

      attrs.xml

      <resources>   
          <attr name="enabledMenuIconColor" format="reference|color"/>
          <attr name="disabledMenuIconColor" format="reference|color"/>
      </resources>
      

      styles.xml or themes.xml

      <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
          <!-- Customize your theme here. -->
          <item name="disabledMenuIconColor">@color/white_30_alpha</item>
          <item name="enabledMenuIconColor">@android:color/white</item>
      

      【讨论】:

      • 很棒的方法,可以在应用程序周围没有太多样板的情况下使用。
      • 你有什么问题?
      • @ExpensiveBelly 本身不是问题,只是公告。
      【解决方案3】:

      如果菜单可见

      menu.findItem(R.id.id_name).setVisible(true);
      

      如果隐藏菜单

      menu.findItem(R.id.id_name).setVisible(false);
      

      【讨论】:

        【解决方案4】:

        如何更新当前菜单以在 AsyncTask 完成时启用或禁用项目。

        在我的用例中,我需要在 AsyncTask 加载数据时禁用我的菜单,然后在加载所有数据后,我需要再次启用所有菜单才能让用户使用它。

        这会阻止应用在加载数据时让用户点击菜单项。

        首先,我声明一个状态变量,如果该变量为0,则显示菜单,如果该变量为1,则隐藏菜单。

        private mMenuState = 1; //I initialize it on 1 since I need all elements to be hidden when my activity starts loading.
        

        然后在我的onCreateOptionsMenu() 中检查这个变量,如果它是 1,我禁用我的所有项目,如果不是,我就全部显示它们

         @Override
            public boolean onCreateOptionsMenu(Menu menu) {
        
                getMenuInflater().inflate(R.menu.menu_galeria_pictos, menu);
        
                if(mMenuState==1){
                    for (int i = 0; i < menu.size(); i++) {
                        menu.getItem(i).setVisible(false);
                    }
                }else{
                     for (int i = 0; i < menu.size(); i++) {
                        menu.getItem(i).setVisible(true);
                    }
                }
        
                return super.onCreateOptionsMenu(menu);
            }
        

        现在,当我的 Activity 启动时,onCreateOptionsMenu() 将只被调用一次,并且我的所有项目都将消失,因为我在开始时为它们设置了状态。

        然后我创建一个 AsyncTask 我在我的onPostExecute() 中将该状态变量设置为 0

        这一步很重要!

        当您调用invalidateOptionsMenu(); 时,它将重新启动onCreateOptionsMenu();

        所以,在将我的状态设置为 0 之后,我只是重绘了所有菜单,但这次我的变量为 0 ,也就是说,所有的菜单将在所有异步过程完成后显示,然后我的用户可以使用菜单。

         public class LoadMyGroups extends AsyncTask<Void, Void, Void> {
        
                @Override
                protected void onPreExecute() {
                    super.onPreExecute();
                    mMenuState = 1; //you can set here the state of the menu too if you dont want to initialize it at global declaration. 
        
                }
        
                @Override
                protected Void doInBackground(Void... voids) {
                   //Background work
        
                    return null;
                }
        
                @Override
                protected void onPostExecute(Void aVoid) {
                    super.onPostExecute(aVoid);
        
                    mMenuState=0; //We change the state and relaunch onCreateOptionsMenu
                    invalidateOptionsMenu(); //Relaunch onCreateOptionsMenu
        
                }
            }
        

        结果

        【讨论】:

          【解决方案5】:
            @Override
                  public boolean onOptionsItemSelected(MenuItem item) {
          
                      switch (item.getItemId()) {
          
                          case R.id.item_id:
          
                                 //Your Code....
          
                                  item.setEnabled(false);
                                  break;
                        }
                      return super.onOptionsItemSelected(item);
               }
          

          【讨论】:

          • 点评来源: 您好,请不要只回答源代码。尝试对您的解决方案如何工作提供一个很好的描述。见:How do I write a good answer?。谢谢
          【解决方案6】:
          @Override
          public boolean onCreateOptionsMenu(Menu menu) {
              // Inflate the menu; this adds items to the action bar if it is present.
              // getMenuInflater().inflate(R.menu.home, menu);
              return false;
          }
          

          【讨论】:

          • 虽然此代码可能会回答 OP 的问题,但几句话的解释将有助于当前和未来的用户更好地理解您的回复。
          【解决方案7】:

          简化@Vikas 版本

          @Override
          public boolean onPrepareOptionsMenu (Menu menu) {
          
              menu.findItem(R.id.example_foobar).setEnabled(isFinalized);
              return true;
          }
          

          【讨论】:

            【解决方案8】:

            无论如何,the documentation 涵盖了所有内容。

            在运行时更改菜单项

            活动创建后, onCreateOptionsMenu() 方法被调用 仅一次,如上所述。这 系统保留和重复使用Menu你 在此方法中定义,直到您的 活动被破坏。如果你想 之后随时更改选项菜单 它是第一次创建的,您必须覆盖 onPrepareOptionsMenu() 方法。 这会将 Menu 对象传递给您 目前存在。这很有用,如果 您想删除、添加、禁用或 启用菜单项取决于 您的应用程序的当前状态。

            例如

            @Override
            public boolean onPrepareOptionsMenu (Menu menu) {
                if (isFinalized) {
                    menu.getItem(1).setEnabled(false);
                    // You can also use something like:
                    // menu.findItem(R.id.example_foobar).setEnabled(false);
                }
                return true;
            }
            

            在 Android 3.0 及更高版本上,当菜单项出现在操作栏中时,选项菜单被视为始终处于打开状态。当有事件发生,你想进行菜单更新时,你必须调用invalidateOptionsMenu()来请求系统调用onPrepareOptionsMenu()

            【讨论】:

            • setEnable() 确实会改变您按下此菜单时发生的情况,但不会改变它的外观(Android 开发人员出了什么问题?)。因此,禁用 更改标题会更清楚,或者最好只使 MenuItem 不可见。
            • 快速提示:返回false 以完全禁用菜单。
            • 加上关于 onPrepareOptionsMenu 的 API 注释清楚地指出:派生类应该始终(!)调用基类实现。你忘记了你的超级电话。
            • 如何知道在运行时添加的 MenuItem 的整数 ID?您只能按名称添加它们。
            【解决方案9】:

            最佳解决方案 当您在导航抽屉上执行时

            @Override
                public boolean onPrepareOptionsMenu(Menu menu) {
                    menu.setGroupVisible(0,false);
                    return true;
                }
            

            【讨论】:

            • 这会隐藏整个菜单,并且无法再次打开它
            【解决方案10】:

            在所有 android 版本上,最简单的方法:使用它来显示一个菜单操作图标为禁用,并使其 FUNCTION 为禁用:

            @Override
            public boolean onPrepareOptionsMenu(Menu menu) {
            
                MenuItem item = menu.findItem(R.id.menu_my_item);
            
                if (myItemShouldBeEnabled) {
                    item.setEnabled(true);
                    item.getIcon().setAlpha(255);
                } else {
                    // disabled
                    item.setEnabled(false);
                    item.getIcon().setAlpha(130);
                }
            }
            

            【讨论】:

            • 既然可以将可见性设置为 false,为什么还要将 alpha 设置为 0?
            • 我没有将 alpha 设置为 0,而是设置为 130。
            • 取决于按钮的上下文。如果按钮通常提供的功能在当前状态下完全不可用,那么是的,可见性应该是不可见/消失的。但是,如果出于任何原因(例如,如果用户成为高级会员、如果用户登录、如果用户连接到互联网等),该按钮通常提供的功能可以使用,那么将其设置为灰色很好因为它让用户知道有一些现有的功能由于某种原因他们无权访问。
            • 在几乎所有用例中将图标设置为不可见并不是更好。如果您有一个组,那么他们最好留在他们的位置并显示为灰色,向用户表明有一个可以在某个程序状态下启用的选项。使事物不可见和不可见并可能导致布局更改是非常愚蠢的。大多数菜单会根据模式将项目灰显而不将其删除是有原因的。
            • 如果菜单不包含图标怎么办?你不能 setAlpha()。
            【解决方案11】:

            通常可以在运行时更改视图的属性:

            (Button) item = (Button) findViewById(R.id.idBut);
            

            然后……

            item.setVisibility(false)
            

            但是

            如果您想从 ContextMenu 修改选项的可见性,按下按钮,您可以激活一个标志,然后在 onCreateContextMenu 中您可以执行以下操作:

             @Override
                    public void onCreateContextMenu(ContextMenu menu, 
                            View v,ContextMenu.ContextMenuInfo menuInfo) {
            
                        super.onCreateContextMenu(menu, v, menuInfo);
            
                            menu.setHeaderTitle(R.string.context_title);
            
                            if (flagIsOn()) {
                                addMenuItem(menu, "Option available", true);
                            } else {
                                Toast.makeText(this, "Option not available", 500).show();
                            }
            
                    }
            

            希望对你有帮助

            【讨论】:

            • 我必须说你错了,我想要禁用菜单项,而不是按钮。
            • 我的回答完成了。这段代码有效,我在我的项目中使用过
            • 感谢您的工作,但您应该正确阅读我已经说过我可以在onCreateContextMenu 方法中更改它的问题。但我想从这个方法访问上下文菜单。
            • onCreateContextMenu 只会被调用一次,但我可以多次单击按钮来启用/禁用菜单项。
            • 是的,但是上下文菜单通常是隐藏的。如果您按“某处按钮”并按我所说的设置标志,则此上下文菜单不可见,并且下次重新加载上下文菜单时,此选项将不可见。另一种选择是做另一种具有相同外观的菜单来用另一种方法处理事件。
            【解决方案12】:

            您可以在创建选项菜单时将项目保存为变量,然后随意更改其属性。

            private MenuItem securedConnection;
            private MenuItem insecuredConnection;
            
            @Override
            public boolean onCreateOptionsMenu(Menu menu) {
                MenuInflater inflater = getMenuInflater();
                inflater.inflate(R.menu.connect_menu, menu);
                securedConnection = menu.getItem(0);
                insecuredConnection =  menu.getItem(1);
                return true;
            }
            
            public void foo(){
                   securedConnection.setEnabled(true);
            }    
            

            【讨论】:

            • 这是对任何安卓版本的正确响应。验证响应仅对 API 11 > 设备有效。
            • 这个我试过了,还是不行。你的意思是onPrepareOptionsMenu