Android: วิธีเปิด / ปิดรายการเมนูตัวเลือกเมื่อคลิกปุ่ม?


127

ฉันสามารถทำได้อย่างง่ายดายเมื่อฉันใช้onCreateOptionsMenuหรือonOptionsItemSelectedวิธีการ

แต่ฉันมีปุ่มอยู่ที่ไหนสักแห่งในหน้าจอและเมื่อคลิกปุ่มนั้นมันควรเปิด / ปิดรายการเมนูบริบท

คำตอบ:


273

อย่างไรก็ตามเอกสารดังกล่าวครอบคลุมทุกสิ่ง

การเปลี่ยนรายการเมนูขณะรันไทม์

เมื่อสร้างกิจกรรมแล้ว onCreateOptionsMenu()เมธอดจะถูกเรียกเพียงครั้งเดียวตามที่อธิบายไว้ข้างต้น ระบบจะเก็บและใช้ซ้ำที่Menuคุณกำหนดในวิธีนี้จนกว่ากิจกรรมของคุณจะถูกทำลาย หากคุณต้องการเปลี่ยนเมนูตัวเลือกเมื่อใดก็ได้หลังจากสร้างครั้งแรกคุณต้องแทนที่onPrepareOptionsMenu()เมธอด สิ่งนี้จะส่งผ่านอ็อบเจ็กต์เมนูตามที่มีอยู่ในปัจจุบัน สิ่งนี้มีประโยชน์หากคุณต้องการลบเพิ่มปิดใช้งานหรือเปิดใช้งานรายการเมนูขึ้นอยู่กับสถานะปัจจุบันของแอปพลิเคชันของคุณ

เช่น

@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ไปปิดการใช้งานเมนูทั้งหมด
Bart Friederichs

5
นอกจากนี้ความคิดเห็นของ API ใน onPrepareOptionsMenu ยังระบุไว้อย่างชัดเจน: คลาสที่ได้รับควรเรียก (!) ไปยังการใช้งานคลาสพื้นฐาน คุณลืมการโทรสุดยอดของคุณที่นั่น
AgentKnopf

เอกสารประกอบ: developer.android.com/guide/topics/ui/…
Jorge

คุณรู้ได้อย่างไรว่า ID จำนวนเต็มของ MenuItem ที่เพิ่มในรันไทม์? คุณสามารถเพิ่มได้โดยใช้ชื่อเท่านั้น
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
เหตุใดจึงตั้งค่า alpha เป็น 0 เมื่อคุณสามารถตั้งค่าการเปิดเผยเป็นเท็จ
MLProgrammer-CiM

8
ฉันไม่ได้ตั้งค่าอัลฟ่าเป็น 0 แต่เป็น 130
แฟรงค์

8
ขึ้นอยู่กับบริบทของปุ่ม หากคุณสมบัติที่ปุ่มใช้งานตามปกติไม่สามารถใช้งานได้อย่างสมบูรณ์ในสถานะปัจจุบันใช่การมองเห็นควรจะมองไม่เห็น / หายไป อย่างไรก็ตามหากคุณลักษณะนี้โดยปกติปุ่มจะให้บริการสามารถใช้งานได้ด้วยเหตุผลใด ๆ ก็ตาม (เช่นหากผู้ใช้กลายเป็นสมาชิกระดับพรีเมียมหากผู้ใช้ลงชื่อเข้าใช้หากผู้ใช้เชื่อมต่ออินเทอร์เน็ต ฯลฯ ) ก็เป็นเรื่องดีที่จะทำให้เป็นสีเทา เพราะมันทำให้ผู้ใช้รู้ว่ามีคุณสมบัติบางอย่างที่พวกเขาไม่สามารถเข้าถึงได้ด้วยเหตุผลบางประการ
yiati

6
การตั้งค่าไอคอนเป็นล่องหนไม่ได้ดีกว่าในเกือบทุกกรณีการใช้งาน ในกรณีที่คุณมีกลุ่มจะดีกว่าพวกเขาจะอยู่ในตำแหน่งของพวกเขาและสีเทาแสดงให้ผู้ใช้ทราบว่ามีตัวเลือกที่สามารถเปิดใช้งานได้ในสถานะของโปรแกรมบางสถานะ การทำให้สิ่งที่มองไม่เห็นและมองไม่เห็นและอาจทำให้เกิดการเปลี่ยนแปลงเค้าโครงนั้นโง่มาก มีสาเหตุที่เมนูส่วนใหญ่เป็นสีเทาและไม่ถูกลบออกโดยขึ้นอยู่กับโหมด
RichieHH

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


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

ตอนนี้เมื่อกิจกรรมของฉันเริ่มต้น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>

แนวทางที่ยอดเยี่ยมที่สามารถใช้ได้โดยไม่ต้องมีต้นแบบมากรอบ ๆ แอป
Arthur

คุณมีปัญหาอะไร
แพง

@ExpensiveBelly ไม่ใช่ปัญหาต่อ se เพียงแค่แจ้งให้สาธารณชนทราบ
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);
     }

จากรีวิว: สวัสดีโปรดอย่าตอบด้วยซอร์สโค้ด พยายามให้คำอธิบายที่ดีเกี่ยวกับวิธีการทำงานของโซลูชันของคุณ ดู: ฉันจะเขียนคำตอบที่ดีได้อย่างไร? . ขอบคุณ
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 ได้ แต่คำอธิบายสองสามคำจะช่วยให้ผู้ใช้ในปัจจุบันและอนาคตเข้าใจคำตอบของคุณได้ดียิ่งขึ้น
ทม


-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

คำตอบของฉันเสร็จสมบูรณ์ รหัสนี้ใช้ได้ผลฉันใช้ในโครงการของฉัน
Eric

1
ขอบคุณสำหรับการทำงาน แต่คุณควรอ่านคำถามอย่างถูกต้องซึ่งฉันได้ระบุไว้แล้วว่าฉันสามารถเปลี่ยนonCreateContextMenuวิธีการได้ แต่ฉันต้องการเข้าถึงเมนูบริบทจากวิธีนี้
Vikas

onCreateContextMenuจะถูกเรียกเพียงครั้งเดียว แต่ฉันสามารถคลิกที่ปุ่มได้หลายครั้งเพื่อเปิด / ปิดรายการเมนู
Vikas

ใช่ แต่โดยปกติแล้วเมนูบริบทจะถูกซ่อนไว้ หากคุณกดปุ่ม 'ที่ไหนสักแห่ง' และตั้งค่าสถานะตามที่ฉันกล่าวไว้เมนูบริบทนี้จะไม่ปรากฏให้เห็นและในครั้งต่อไปที่คุณโหลดเมนูบริบทใหม่ตัวเลือกนี้จะมองไม่เห็น อีกทางเลือกหนึ่งคือทำเมนูอื่นที่มีลักษณะเหมือนกันเพื่อจัดการเหตุการณ์ด้วยวิธีการอื่น
Eric
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.