Android: Làm thế nào để bật / tắt mục menu tùy chọn khi nhấp vào nút?


127

Tôi có thể dễ dàng làm điều đó khi tôi đang sử dụng onCreateOptionsMenuhoặc onOptionsItemSelectedphương pháp.

Nhưng tôi có một nút ở đâu đó trên màn hình và khi nhấp vào nút đó, nó sẽ bật / tắt các mục menu ngữ cảnh.

Câu trả lời:


272

Dù sao, tài liệu bao gồm tất cả mọi thứ.

Thay đổi các mục menu trong thời gian chạy

Khi hoạt động được tạo, onCreateOptionsMenu()phương thức chỉ được gọi một lần, như được mô tả ở trên. Hệ thống giữ và sử dụng lại Menubạn xác định trong phương thức này cho đến khi hoạt động của bạn bị hủy. Nếu bạn muốn thay đổi Menu Tùy chọn bất cứ lúc nào sau khi được tạo lần đầu tiên, bạn phải ghi đè onPrepareOptionsMenu()phương thức. Điều này chuyển cho bạn đối tượng Menu như nó hiện đang tồn tại. Điều này hữu ích nếu bạn muốn xóa, thêm, tắt hoặc bật các mục menu tùy thuộc vào trạng thái hiện tại của ứng dụng của bạn.

Ví dụ

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

Trên Android 3.0 trở lên, menu tùy chọn được coi là luôn mở khi các mục menu được hiển thị trên thanh hành động. Khi một sự kiện xảy ra và bạn muốn thực hiện cập nhật menu, bạn phải gọi invalidateOptionsMenu()để yêu cầu hệ thống gọi onPrepareOptionsMenu().


2
setEnable()không thay đổi những gì xảy ra khi bạn nhấn menu này nhưng không thay đổi giao diện (có gì sai, nhà phát triển Android?). Vì vậy, rõ ràng hơn là vô hiệu hóa thay đổi tiêu đề, hoặc tốt nhất là chỉ làm cho MenuItemvô hình.
Vlad

19
Mẹo nhanh: quay lại falseđể tắt hoàn toàn menu.
Bart Friederichs

5
Cộng với nhận xét API trên onPrepareOptionsMothy nêu rõ: Các lớp phái sinh phải luôn luôn gọi (!) Để thực hiện lớp cơ sở. Bạn đã quên cuộc gọi siêu của bạn ở đó.
Đặc vụKnopf


Làm thế nào để bạn biết ID số nguyên của MenuItem được thêm vào lúc chạy? Bạn chỉ có thể thêm chúng theo tên.
Antonio Sesto

66

Trên tất cả các phiên bản Android, cách dễ nhất: sử dụng điều này để hiển thị biểu tượng hành động menu bị vô hiệu hóa và làm cho nó CHỨC NĂNG cũng bị vô hiệu hóa:

@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
Tại sao đặt alpha thành 0 khi bạn có thể đặt mức độ hiển thị thành sai?
MLProgrammer-CiM

8
Tôi không đặt alpha thành 0, mà là 130.
Frank

8
Phụ thuộc vào bối cảnh của nút. Nếu tính năng mà nút thường phục vụ là hoàn toàn không thể sử dụng được ở trạng thái hiện tại, thì có, khả năng hiển thị sẽ vô hình / biến mất. Tuy nhiên, nếu tính năng mà nút thường phục vụ COULD có thể sử dụng được vì bất kỳ lý do gì (ví dụ: Nếu người dùng trở thành thành viên cao cấp, nếu người dùng đăng nhập, nếu người dùng kết nối với internet, v.v.) thì thật tuyệt khi nó bị mờ đi bởi vì sau đó nó cho phép người dùng biết có một số tính năng hiện có mà họ không có quyền truy cập vì một số lý do.
yiati

6
Đặt biểu tượng thành vô hình không tốt hơn trong hầu hết các trường hợp sử dụng. Trong trường hợp bạn có một nhóm, tốt hơn là họ giữ nguyên vị trí của mình và chuyển sang màu xám cho người dùng biết rằng có một tùy chọn có thể được bật trong trạng thái chương trình nhất định. làm cho mọi thứ trở nên vô hình và vô hình và có thể gây ra thay đổi bố cục là rất ngớ ngẩn. Có một lý do hầu hết các menu màu xám ra các mục và không loại bỏ chúng tùy thuộc vào chế độ.
RichieHH

1
Làm thế nào nếu menu không chứa biểu tượng? Bạn không thể đặt Alpha ().
Latief Anwar

42

Bạn có thể lưu mục dưới dạng một biến khi tạo menu tùy chọn và sau đó thay đổi thuộc tính của nó theo ý muốn.

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

Đó là phản hồi chính xác cho bất kỳ phiên bản Android nào. Phản hồi được xác thực chỉ hợp lệ cho các thiết bị API 11>.
Marco HC

2
Tôi đã thử điều này, và nó không hoạt động. Ý bạn là onPrepareOptionsMenusao
Christopher Pickslay

6

đơn giản hóa phiên bản @Vikas

@Override
public boolean onPrepareOptionsMenu (Menu menu) {

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

4

Cách cập nhật menu hiện tại để bật hoặc tắt các mục khi AsyncTask hoàn tất.

Trong trường hợp sử dụng của tôi, tôi cần phải tắt menu trong khi AsyncTask của tôi đang tải dữ liệu, sau đó sau khi tải tất cả dữ liệu, tôi cần bật lại tất cả menu để cho phép người dùng sử dụng.

Điều này đã ngăn ứng dụng cho phép người dùng nhấp vào các mục menu trong khi dữ liệu đang tải.

Đầu tiên, tôi khai báo một biến trạng thái, nếu biến là 0 thì menu được hiển thị, nếu biến đó là 1 thì menu bị ẩn.

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

Sau đó, trong onCreateOptionsMenu()kiểm tra của tôi, tôi sẽ kiểm tra biến này, nếu đó là 1 tôi vô hiệu hóa tất cả các mục của mình, nếu không, tôi chỉ hiển thị tất cả

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

Bây giờ, khi Hoạt động của tôi bắt đầu, onCreateOptionsMenu()sẽ được gọi chỉ một lần và tất cả các mục của tôi sẽ biến mất vì tôi thiết lập trạng thái cho chúng khi bắt đầu.

Sau đó, tôi tạo AsyncTask nơi tôi đặt biến trạng thái đó thành 0 trong onPostExecute()

Bước này rất quan trọng!

Khi bạn gọi invalidateOptionsMenu();nó sẽ khởi động lạionCreateOptionsMenu();

Vì vậy, sau khi thiết lập trạng thái của tôi thành 0, tôi chỉ vẽ lại tất cả các menu nhưng lần này với biến của tôi là 0, có nghĩa là, tất cả các menu sẽ được hiển thị sau khi tất cả quá trình không đồng bộ được thực hiện, và sau đó người dùng của tôi có thể sử dụng menu .

 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

        }
    }

Các kết quả

nhập mô tả hình ảnh ở đây


2

giải pháp tốt nhất khi bạn thực hiện trên ngăn kéo điều hướng

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

Điều này ẩn toàn bộ menu và khiến nó không thể mở lại
MrStahlfelge

2

Một câu trả lời hiện đại hơn cho một câu hỏi cũ:

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>

Cách tiếp cận tuyệt vời có thể được sử dụng mà không cần nhiều bản tóm tắt xung quanh ứng dụng.
Arthur

Bạn gặp vấn đề gì?
ExpensiveBelly

@ExpensiveBelly không phải là vấn đề mỗi se, chỉ cần thông báo công khai.
Big 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);
     }

Từ đánh giá: Xin chào, xin vui lòng không trả lời chỉ với mã nguồn. Cố gắng cung cấp một mô tả hay về cách giải pháp của bạn hoạt động. Xem: Làm thế nào để tôi viết một câu trả lời tốt? . Cảm ơn
sunıɔ qɐp

1

Những gì tôi đã làm là lưu một tham chiếu đến Menu tại onCreateOptionsMenu. Điều này tương tự như câu trả lời của nir ngoại trừ thay vì lưu từng mục riêng lẻ, tôi đã lưu toàn bộ menu.

Khai báo một Menu Menu toolbarMenu;.

Sau đó, onCreateOptionsMenulưu menu vào biến của bạn

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

Bây giờ bạn có thể truy cập menu của bạn và tất cả các mục của nó bất cứ lúc nào bạn muốn. 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
Mặc dù mã này có thể trả lời câu hỏi của OP, một vài lời giải thích sẽ giúp người dùng hiện tại và tương lai hiểu rõ hơn câu trả lời của bạn.
Thơm


-4

Nói chung có thể thay đổi các thuộc tính của chế độ xem của bạn trong thời gian chạy:

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

và sau đó...

item.setVisibility(false)

nhưng

nếu bạn muốn sửa đổi mức độ hiển thị của các tùy chọn từ ContextMothy, khi nhấn nút, bạn có thể kích hoạt cờ và sau đó trong onCreateContextMothy, bạn có thể làm điều gì đó như sau:

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

        }

Tôi hi vọng cái này giúp được


Tôi phải nói rằng bạn đang hiểu sai, tôi muốn mục menu bị vô hiệu hóa, không phải Nút.
Vikas

Câu trả lời của tôi đã hoàn thành. Mã này hoạt động, tôi đã sử dụng trong các dự án của mình
Eric

1
Vâng cảm ơn vì công việc, nhưng bạn nên đọc đúng câu hỏi mà tôi đã tuyên bố rằng tôi có thể thay đổi nó theo onCreateContextMenuphương pháp. Nhưng tôi muốn truy cập menu ngữ cảnh bên ngoài phương thức này.
Vikas

onCreateContextMenusẽ chỉ được gọi một lần, nhưng tôi có thể nhấp vào nút nhiều thời gian để bật / tắt mục menu.
Vikas

Có, nhưng menu ngữ cảnh thường được thực hiện để ẩn. Nếu bạn nhấn 'nút ở đâu đó' và đặt cờ như tôi đã nói, menu ngữ cảnh này sẽ không hiển thị và lần sau khi bạn tải lại menu ngữ cảnh của mình, tùy chọn này sẽ ẩn đi. Một lựa chọn khác là thực hiện một loại menu khác có cùng diện mạo để xử lý các sự kiện bằng các phương thức khác.
Eric
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.