Android: как включить / отключить пункт меню опций при нажатии кнопки?


127

Я легко могу это сделать, когда использую методы onCreateOptionsMenuили onOptionsItemSelected.

Но у меня есть кнопка где-то на экране, и при нажатии на эту кнопку она должна включать / отключать элементы контекстного меню.

Ответы:


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невидимым.
Влад

19
Совет: вернитесь, falseчтобы полностью отключить меню.
Барт Фридрихс

5
Кроме того, в комментарии API к onPrepareOptionsMenu четко сказано: производные классы всегда (!) Должны вызывать реализацию базового класса. Вы забыли там свой супер-звонок.
AgentKnopf


Как узнать целочисленный идентификатор MenuItem, добавленного во время выполнения? Вы можете добавлять их только по имени.
Антонио Сесто,

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
Зачем устанавливать альфа равным 0, если вы можете установить для видимости значение false?
MLProgrammer-CiM

8
Я устанавливаю альфа не на 0, а на 130.
Фрэнк

8
Зависит от контекста кнопки. Если функция, которую обычно обслуживает кнопка, полностью непригодна для использования в текущем состоянии, то да, видимость должна быть невидимой / отсутствовать. Однако, если функция, которую обычно обслуживает кнопка, МОЖЕТ быть использована по каким-либо причинам (например, если пользователь становится членом премиум-класса, если пользователь входит в систему, если пользователь подключается к Интернету и т. Д.), Тогда было бы хорошо, если бы она была выделена серым цветом. потому что тогда он позволяет пользователю узнать, что есть какая-то существующая функция, к которой у него по какой-то причине нет доступа.
yiati

6
Установка невидимого значка не лучше почти во всех случаях использования. В случае, если у вас есть группа, лучше, чтобы они оставались на своих местах, а серый цвет указывает пользователю, что есть опция, которую можно включить в определенном состоянии программы. делать вещи невидимыми и невидимыми и, вероятно, вызывать изменения макета, очень глупо. Есть причина, по которой в большинстве меню элементы отображаются серым цветом и не удаляются в зависимости от режима.
RichieHH 01

1
Как быть, если в меню нет значка? Вы не можете setAlpha ().
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

6

упростить версию @Vikas

@Override
public boolean onPrepareOptionsMenu (Menu menu) {

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

5

Как обновить текущее меню, чтобы включить или отключить элементы после выполнения 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, где устанавливаю для этой переменной состояния значение 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

@ExmerceBelly сама по себе не проблема, просто публичное уведомление.
Большой МакЛардж Огромный

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, несколько слов пояснения помогут нынешним и будущим пользователям еще лучше понять ваш ответ.
Том

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

        }

надеюсь, это поможет


Я должен сказать, что вы ошибаетесь, я хочу, чтобы был отключен пункт меню, а не кнопка.
Vikas

мой ответ закончен. Этот код работает, я использовал в своих проектах
Эрик,

1
Что ж, спасибо за работу, но вы должны внимательно прочитать вопрос, который я уже сказал, что могу изменить его в onCreateContextMenuметоде. Но я хочу получить доступ к контекстному меню вне этого метода.
Vikas

onCreateContextMenuбудет вызываться только один раз, но я могу нажимать кнопку много времени, чтобы включить / отключить пункт меню.
Vikas

Да, но обычно контекстное меню скрыто. Если вы нажмете кнопку «где-нибудь» и установите флаг, как я уже сказал, это контекстное меню не будет отображаться, и в следующий раз, когда вы перезагрузите контекстное меню, этот параметр будет невидимым. Другой вариант - создать другой вид меню с таким же внешним видом для обработки событий другими методами.
Эрик
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.