Android:如何在单击按钮时启用/禁用选项菜单项?


127

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

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

Answers:


272

无论如何,文档涵盖了所有内容。

在运行时更改菜单项

创建活动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()


2
setEnable()确实会改变您按此菜单时发生的情况,但不会改变外观(Android开发人员怎么了?)。因此,禁用更改标题,或者最好只是使其MenuItem不可见,这是很清楚的。
弗拉德(Vlad)

19
快速提示:返回false以完全禁用菜单。
巴特·弗里德里希斯

5
加上对onPrepareOptionsMenu的API注释明确指出:派生类应始终(!)调用基类实现。您忘记了在那里的超级通话。
AgentKnopf


您如何知道在运行时添加的MenuItem的整数ID?您只能按名称添加它们。
Antonio Sesto

66

在所有android版本上,最简单的方法:使用此按钮将菜单操作图标显示为禁用,并将其功能设置为禁用:

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

1
可以将可见性设置为false时,为什么将alpha设置为0?
MLProgrammer-CiM 2014年

8
我没有将alpha设置为0,而是设置为130。–
Frank

8
取决于按钮的上下文。如果按钮在当前状态下通常无法正常使用,则是,可见性应该为不可见/消失。但是,如果出于任何原因(例如,如果用户成为高级会员,如果用户登录,如果用户连接到互联网等),该按钮通常可以正常使用的功能,则将其设为灰色非常好因为这样它可以让用户知道由于某种原因他们无法访问某些现有功能。
yiati 2014年

6
在几乎所有用例中,将图标设置为不可见并不是更好。如果您有一个组,则最好将它们保持在原位,并且以灰色显示给用户,表明可以在某个程序状态下启用某个选项。使事物变得不可见和不可见,并可能导致布局更改非常愚蠢。有一个原因是大多数菜单会根据项目的不同使项目变灰,而不会将其删除。
RichieHH 2014年

1
如果菜单不包含图标怎么办?您不能设置Alpha()。
Latief Anwar

42

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

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

这是对任何Android版本的正确回应。经过验证的响应仅对API 11>设备有效。
Marco HC

2
我已经尝试过了,但是没有用。你是说onPrepareOptionsMenu
Christopher Pickslay 2014年

6

简化@Vikas版本

@Override
public boolean onPrepareOptionsMenu (Menu menu) {

    menu.findItem(R.id.example_foobar).setEnabled(isFinalized);
    return true;
}

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

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

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

这一步很重要!

通话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

        }
    }

结果

在此处输入图片说明


2

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

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

这隐藏了整个菜单,无法再次打开它
MrStahlfelge

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,

@ExpensiveBelly本身不是问题,只是公告。
大McLargeHuge

1
  @Override
        public boolean onOptionsItemSelected(MenuItem item) {

            switch (item.getItemId()) {

                case R.id.item_id:

                       //Your Code....

                        item.setEnabled(false);
                        break;
              }
            return super.onOptionsItemSelected(item);
     }

点评来源:您好,请不要仅提供源代码。尝试提供有关您的解决方案如何工作的很好的描述。请参阅:我如何写一个好的答案?。谢谢
sɐunıɔןɐqɐp

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


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

2
尽管此代码可以回答OP的问题,但仅需说明几句,便可以帮助当前和将来的用户更好地理解您的回答。
汤姆(Thom)

0

如果可见菜单

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

如果隐藏菜单

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

-4

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

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

        }

我希望这有帮助


我必须说你错了,我想禁用菜单项,而不是Button。
维卡斯

我的回答完成了。此代码它的工作原理,我在我的项目已经使用
埃里克·

1
好的,谢谢您的工作,但是您应该正确地阅读我已经说过可以更改onCreateContextMenu方法的问题。但是我想从此方法外部访问上下文菜单。
维卡斯

onCreateContextMenu只会被调用一次,但是我可以点击按钮很多时间来启用/禁用菜单项。
维卡斯

是的,但是上下文菜单通常可以隐藏。如果您按“某处按钮”并按照我说的那样设置标志,则此上下文菜单不可见,并且下次重新加载上下文菜单时,此选项将不可见。另一种选择是执行具有相同外观的另一种菜单,以使用其他方法处理事件。
艾瑞克(Eric)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.