เพิ่มเมนู

ลองใช้วิธีเขียน
Jetpack Compose เป็นชุดเครื่องมือ UI ที่แนะนําสําหรับ Android ดูวิธีเพิ่มคอมโพเนนต์ใน Compose

เมนูเป็นคอมโพเนนต์อินเทอร์เฟซผู้ใช้ทั่วไปในแอปหลายประเภท หากต้องการให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่คุ้นเคยและสอดคล้องกัน ให้ใช้ Menu API เพื่อแสดงการดําเนินการของผู้ใช้และตัวเลือกอื่นๆ ในกิจกรรม

รูปภาพแสดงตัวอย่างเมนูรายการเพิ่มเติม
รูปที่ 1 เมนูที่เรียกให้แสดงด้วยการแตะไอคอน ซึ่งจะปรากฏใต้ไอคอนเมนูรายการเพิ่มเติม

เอกสารนี้แสดงวิธีสร้างเมนูหรือการแสดงผลการดำเนินการพื้นฐาน 3 ประเภทใน Android ทุกเวอร์ชัน

เมนูตัวเลือกและแถบแอป
เมนูตัวเลือกคือคอลเล็กชันรายการเมนูหลักสําหรับกิจกรรม ซึ่งเป็นตําแหน่งที่คุณวางการดําเนินการที่มีผลกับแอปโดยรวม เช่น "ค้นหา" "เขียนอีเมล" และ "การตั้งค่า"

ดูส่วนสร้างเมนูตัวเลือก

เมนูตามบริบทและโหมดการดำเนินการตามบริบท
เมนูตามบริบทคือเมนูแบบลอยที่ปรากฏขึ้นเมื่อผู้ใช้แตะองค์ประกอบค้างไว้ ซึ่งจะแสดงการดำเนินการที่ส่งผลต่อเนื้อหาหรือเฟรมบริบทที่เลือก

โหมดการดำเนินการตามบริบทจะแสดงรายการการดำเนินการที่ส่งผลต่อเนื้อหาที่เลือกในแถบด้านบนของหน้าจอ และช่วยให้ผู้ใช้เลือกรายการได้หลายรายการ

ดูส่วนสร้างเมนูตามบริบท

เมนูป๊อปอัป
เมนูป๊อปอัปจะแสดงรายการแนวตั้งของรายการที่ยึดกับมุมมองที่เรียกเมนู ซึ่งเหมาะสำหรับการแสดงการดำเนินการจำนวนมากที่เกี่ยวข้องกับเนื้อหาที่เฉพาะเจาะจง หรือแสดงตัวเลือกสำหรับส่วนที่สองของคำสั่ง การดำเนินการในเมนูป๊อปอัปจะไม่ส่งผลต่อเนื้อหาที่เกี่ยวข้องโดยตรง การดำเนินการตามบริบทมีไว้เพื่อดำเนินการดังกล่าว แต่เมนูป๊อปอัปมีไว้สําหรับการดําเนินการเพิ่มเติมที่เกี่ยวข้องกับภูมิภาคของเนื้อหาในกิจกรรม

โปรดดูส่วนสร้างเมนูป๊อปอัป

กำหนดเมนูใน XML

สำหรับเมนูทุกประเภท Android มีรูปแบบ XML มาตรฐานในการกำหนดรายการเมนู แทนที่จะสร้างเมนูในโค้ดของกิจกรรม ให้กําหนดเมนูและรายการทั้งหมดใน XML ทรัพยากรเมนู จากนั้นคุณสามารถพองทรัพยากรเมนูโดยโหลดเป็นMenuออบเจ็กต์ในกิจกรรมหรือแฟรกเมนต์

การใช้แหล่งข้อมูลเมนูเป็นแนวทางปฏิบัติแนะนำเนื่องด้วยเหตุผลต่อไปนี้

  • โครงสร้างเมนูใน XML ช่วยให้มองเห็นภาพได้ง่ายขึ้น
  • ซึ่งจะแยกเนื้อหาของเมนูออกจากโค้ดลักษณะการทํางานของแอป
  • ซึ่งช่วยให้คุณสร้างการกำหนดค่าเมนูทางเลือกสำหรับแพลตฟอร์มเวอร์ชันต่างๆ ขนาดหน้าจอ และการกําหนดค่าอื่นๆ ได้โดยใช้ประโยชน์จากเฟรมเวิร์กทรัพยากรแอป

หากต้องการกำหนดเมนู ให้สร้างไฟล์ XML ในไดเรกทอรี res/menu/ ของโปรเจ็กต์ แล้วสร้างเมนูด้วยองค์ประกอบต่อไปนี้

<menu>
กำหนด Menu ซึ่งเป็นคอนเทนเนอร์สำหรับรายการในเมนู องค์ประกอบ <menu> ต้องเป็นโหนดรูทของไฟล์ และสามารถมีองค์ประกอบ <item> และ <group> อย่างน้อย 1 รายการ
<item>
สร้าง MenuItem ซึ่งแสดงรายการเดียวในเมนู องค์ประกอบนี้อาจมีองค์ประกอบ <menu> ที่ฝังอยู่เพื่อสร้างเมนูย่อย
<group>
คอนเทนเนอร์ที่ไม่บังคับซึ่งมองไม่เห็นสำหรับองค์ประกอบ <item> ซึ่งช่วยให้คุณจัดหมวดหมู่รายการเมนูเพื่อให้มีพร็อพเพอร์ตี้ร่วมกัน เช่น สถานะใช้งานอยู่และระดับการเข้าถึง ดูข้อมูลเพิ่มเติมได้ที่ส่วนสร้างกลุ่มเมนู

ตัวอย่างเมนูชื่อ game_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/new_game"
          android:icon="@drawable/ic_new_game"
          android:title="@string/new_game"
          app:showAsAction="ifRoom"/>
    <item android:id="@+id/help"
          android:icon="@drawable/ic_help"
          android:title="@string/help" />
</menu>

องค์ประกอบ <item> รองรับแอตทริบิวต์หลายรายการที่คุณสามารถใช้เพื่อกำหนดลักษณะที่ปรากฏและลักษณะการทํางานของรายการ รายการในเมนูก่อนหน้าจะมีแอตทริบิวต์ต่อไปนี้

android:id
รหัสทรัพยากรที่ไม่ซ้ำกันสำหรับรายการ ซึ่งช่วยให้แอปจดจำรายการได้เมื่อผู้ใช้เลือก
android:icon
การอ้างอิงไปยังไฟล์ที่วาดได้เพื่อใช้เป็นไอคอนของรายการ
android:title
การอ้างอิงสตริงที่จะใช้เป็นชื่อของรายการ
android:showAsAction
ข้อกำหนดเกี่ยวกับเวลาและวิธีที่รายการนี้จะปรากฏเป็นรายการการดำเนินการในแถบแอป

แอตทริบิวต์เหล่านี้เป็นแอตทริบิวต์ที่สําคัญที่สุดที่คุณใช้ แต่ยังมีแอตทริบิวต์อื่นๆ อีกมากมาย ดูข้อมูลเกี่ยวกับแอตทริบิวต์ที่รองรับทั้งหมดได้ในเอกสารประกอบเกี่ยวกับทรัพยากรเมนู

คุณเพิ่มเมนูย่อยลงในรายการในเมนูใดก็ได้ด้วยการเพิ่มองค์ประกอบ <menu> เป็นองค์ประกอบย่อยของ <item> เมนูย่อยมีประโยชน์เมื่อแอปของคุณมีฟังก์ชันมากมายที่จัดระเบียบเป็นหัวข้อต่างๆ ได้ เช่น รายการในแถบเมนูของแอปบน PC เช่น ไฟล์ แก้ไข และดู โปรดดูตัวอย่างต่อไปนี้

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/file"
          android:title="@string/file" >
        <!-- "file" submenu -->
        <menu>
            <item android:id="@+id/create_new"
                  android:title="@string/create_new" />
            <item android:id="@+id/open"
                  android:title="@string/open" />
        </menu>
    </item>
</menu>

หากต้องการใช้เมนูในกิจกรรม ให้ _inflate_ ทรัพยากรเมนู ซึ่งจะแปลงทรัพยากร XML ให้เป็นออบเจ็กต์ที่โปรแกรมได้โดยใช้ MenuInflater.inflate() ส่วนต่อไปนี้แสดงวิธีขยายเมนูสำหรับเมนูแต่ละประเภท

สร้างเมนูตัวเลือก

เมนูตัวเลือก เช่น เมนูที่แสดงในรูปที่ 1 คือที่ที่คุณใส่การดำเนินการและตัวเลือกอื่นๆ ที่เกี่ยวข้องกับบริบทของกิจกรรมปัจจุบัน เช่น "ค้นหา" "เขียนอีเมล" และ "การตั้งค่า"

รูปภาพแสดงแถบแอปสําหรับแอป Google ชีต
รูปที่ 2 แอป Google ชีตที่แสดงปุ่มหลายปุ่ม รวมถึงปุ่มการดำเนินการแบบ Overflow

คุณสามารถประกาศรายการสำหรับเมนูตัวเลือกจากคลาสย่อยของ Activity หรือคลาสย่อยของ Fragment หากทั้งกิจกรรมและข้อมูลโค้ดประกาศรายการสำหรับเมนูตัวเลือก ระบบจะรวมรายการเหล่านั้นไว้ใน UI รายการของกิจกรรมจะปรากฏขึ้นก่อน ตามด้วยรายการของข้อมูลโค้ดแต่ละรายการตามลำดับที่เพิ่มข้อมูลโค้ดลงในกิจกรรม หากจําเป็น คุณสามารถจัดเรียงรายการเมนูใหม่โดยใช้แอตทริบิวต์ android:orderInCategory ใน <item> แต่ละรายการที่ต้องการย้าย

หากต้องการระบุเมนูตัวเลือกสําหรับกิจกรรม ให้ลบล้าง onCreateOptionsMenu() แต่ละรายการจะมี callback ของตัวเอง onCreateOptionsMenu() ในวิธีการนี้ คุณสามารถขยายทรัพยากรเมนูที่กำหนดไว้ใน XML ไปยัง Menu ที่ระบุไว้ใน callback ดังที่แสดงในตัวอย่างต่อไปนี้

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    val inflater: MenuInflater = menuInflater
    inflater.inflate(R.menu.game_menu, menu)
    return true
}

Java

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

นอกจากนี้ คุณยังเพิ่มรายการในเมนูโดยใช้ add() และดึงข้อมูลรายการด้วย findItem() เพื่อแก้ไขพร็อพเพอร์ตี้ด้วย MenuItem API ได้ด้วย

จัดการเหตุการณ์การคลิก

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

Kotlin

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    // Handle item selection.
    return when (item.itemId) {
        R.id.new_game -> {
            newGame()
            true
        }
        R.id.help -> {
            showHelp()
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection.
    switch (item.getItemId()) {
        case R.id.new_game:
            newGame();
            return true;
        case R.id.help:
            showHelp();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

เมื่อจัดการรายการเมนูเรียบร้อยแล้ว ให้แสดงผล true หากคุณไม่ได้จัดการรายการเมนู ให้เรียกใช้การใช้งานคลาสซุปเปอร์คลาสของ onOptionsItemSelected() การใช้งานเริ่มต้นจะแสดงผลเป็นค่าเท็จ

หากกิจกรรมมีข้อมูลโค้ด ระบบจะเรียกใช้ onOptionsItemSelected() สำหรับกิจกรรมก่อน จากนั้นเรียกใช้สำหรับข้อมูลโค้ดแต่ละรายการตามลำดับที่เพิ่มข้อมูลโค้ดจนกว่าข้อมูลโค้ดรายการใดรายการหนึ่งจะแสดงผลเป็น true หรือเรียกใช้ข้อมูลโค้ดทั้งหมดแล้ว

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

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

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

ระบบจะถือว่าเมนูตัวเลือกเปิดอยู่เสมอเมื่อมีการแสดงรายการเมนูในแถบแอป เมื่อเกิดเหตุการณ์ขึ้นและคุณต้องการอัปเดตเมนู ให้เรียกใช้ invalidateOptionsMenu() เพื่อขอให้ระบบเรียก onPrepareOptionsMenu()

สร้างเมนูตามบริบท

รูปภาพแสดงเมนูตามบริบทแบบลอย
รูปที่ 3 เมนูตามบริบทแบบลอย

เมนูตามบริบทมีการดำเนินการที่ส่งผลต่อรายการหรือเฟรมบริบทที่เฉพาะเจาะจงใน UI คุณระบุเมนูตามบริบทสำหรับมุมมองใดก็ได้ แต่มักใช้กับรายการในRecylerViewหรือคอลเล็กชันมุมมองอื่นๆ ที่ผู้ใช้สามารถดำเนินการกับแต่ละรายการได้โดยตรง

การดำเนินการตามบริบทมี 2 วิธีดังนี้

  • ในเมนูตามบริบทแบบลอย เมนูจะปรากฏเป็นรายการรายการเมนูที่ลอยอยู่ ซึ่งคล้ายกับกล่องโต้ตอบ เมื่อผู้ใช้แตะและกดค้างไว้ที่มุมมองที่ประกาศรองรับเมนูตามบริบท ผู้ใช้สามารถดําเนินการตามบริบทกับรายการได้ครั้งละ 1 รายการ
  • ในโหมดการดำเนินการตามบริบท โหมดนี้เป็นการใช้งาน ActionMode ของระบบที่แสดงแถบการดำเนินการตามบริบทหรือ CAB ที่ด้านบนของหน้าจอพร้อมรายการการดำเนินการที่ส่งผลต่อรายการที่เลือก เมื่อโหมดนี้ทำงานอยู่ ผู้ใช้จะดำเนินการกับหลายรายการพร้อมกันได้ หากแอปของคุณรองรับ

หมายเหตุ: เมนูตามบริบทไม่รองรับแป้นพิมพ์ลัดของรายการและไอคอนของรายการ

สร้างเมนูตามบริบทแบบลอย

หากต้องการแสดงเมนูตามบริบทแบบลอย ให้ทําดังนี้

  1. ลงทะเบียน View ที่เชื่อมโยงกับเมนูตามบริบทโดยเรียกใช้ registerForContextMenu() และส่ง View

    หากกิจกรรมใช้ RecyclerView และคุณต้องการให้แต่ละรายการแสดงเมนูตามบริบทเดียวกัน ให้ลงทะเบียนรายการทั้งหมดสำหรับเมนูตามบริบทโดยส่ง RecyclerView ไปยัง registerForContextMenu()

  2. ใช้วิธี onCreateContextMenu() ใน Activity หรือ Fragment

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

    Kotlin

        override fun onCreateContextMenu(menu: ContextMenu, v: View,
                                menuInfo: ContextMenu.ContextMenuInfo) {
            super.onCreateContextMenu(menu, v, menuInfo)
            val inflater: MenuInflater = menuInflater
            inflater.inflate(R.menu.context_menu, menu)
        }
        

    Java

        @Override
        public void onCreateContextMenu(ContextMenu menu, View v,
                                        ContextMenuInfo menuInfo) {
            super.onCreateContextMenu(menu, v, menuInfo);
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.context_menu, menu);
        }
        

    MenuInflater ให้คุณขยายเมนูตามบริบทจากทรัพยากรเมนู พารามิเตอร์ของเมธอดการเรียกกลับมี View ที่ผู้ใช้เลือกและออบเจ็กต์ ContextMenu.ContextMenuInfo ที่แสดงข้อมูลเพิ่มเติมเกี่ยวกับรายการที่เลือก หากกิจกรรมมีมุมมองหลายมุมมองที่แต่ละมุมมองมีเมนูบริบทต่างกัน คุณอาจใช้พารามิเตอร์เหล่านี้เพื่อระบุเมนูบริบทที่จะขยาย

  3. ติดตั้งใช้งาน onContextItemSelected() ดังที่แสดงในตัวอย่างต่อไปนี้ เมื่อผู้ใช้เลือกรายการเมนู ระบบจะเรียกใช้เมธอดนี้เพื่อให้คุณดําเนินการที่เหมาะสมได้

    Kotlin

        override fun onContextItemSelected(item: MenuItem): Boolean {
            val info = item.menuInfo as AdapterView.AdapterContextMenuInfo
            return when (item.itemId) {
                R.id.edit -> {
                    editNote(info.id)
                    true
                }
                R.id.delete -> {
                    deleteNote(info.id)
                    true
                }
                else -> super.onContextItemSelected(item)
            }
        }
        

    Java

        @Override
        public boolean onContextItemSelected(MenuItem item) {
            AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
            switch (item.getItemId()) {
                case R.id.edit:
                    editNote(info.id);
                    return true;
                case R.id.delete:
                    deleteNote(info.id);
                    return true;
                default:
                    return super.onContextItemSelected(item);
            }
        }
        

    เมธอด getItemId() จะค้นหารหัสของรายการเมนูที่เลือก ซึ่งคุณกำหนดให้กับรายการเมนูแต่ละรายการใน XML โดยใช้แอตทริบิวต์ android:id ดังที่แสดงในกำหนดเมนูใน XML

    เมื่อจัดการรายการเมนูเรียบร้อยแล้ว ให้แสดงผล true หากคุณไม่ได้จัดการรายการเมนู ให้ส่งรายการเมนูไปยังการใช้งานของซุปเปอร์คลาส หากกิจกรรมมีข้อมูลโค้ดที่แยกส่วน กิจกรรมจะได้รับการเรียกกลับนี้ก่อน เมื่อเรียกใช้ซุปเปอร์คลาสเมื่อไม่มีการแฮนเดิล ระบบจะส่งเหตุการณ์ไปยังเมธอดการเรียกคืนที่เกี่ยวข้องในแต่ละแฟรกเมนต์ทีละรายการตามลําดับที่เพิ่มแต่ละแฟรกเมนต์จนกว่าระบบจะแสดงผล true หรือ false การใช้งานเริ่มต้นสำหรับ Activity และ android.app.Fragment จะแสดงผลเป็น false ดังนั้นให้เรียกใช้ซุปเปอร์คลาสเสมอเมื่อไม่จัดการ

ใช้โหมดการดำเนินการตามบริบท

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

สําหรับมุมมองที่แสดงการดําเนินการตามบริบท ปกติแล้วคุณจะเรียกใช้โหมดการดําเนินการตามบริบทเมื่อเกิดเหตุการณ์อย่างใดอย่างหนึ่งหรือทั้ง 2 เหตุการณ์ต่อไปนี้

  • ผู้ใช้แตะมุมมองค้างไว้
  • ผู้ใช้เลือกช่องทําเครื่องหมายหรือคอมโพเนนต์ UI ที่คล้ายกันภายในมุมมอง

วิธีที่แอปเรียกใช้โหมดการดำเนินการตามบริบทและกำหนดลักษณะการทํางานสําหรับการดําเนินการแต่ละรายการจะขึ้นอยู่กับการออกแบบของคุณ โดยการออกแบบมี 2 แบบดังนี้

  • สําหรับการดําเนินการตามบริบทในมุมมองแต่ละมุมมองที่กําหนดเอง
  • สําหรับการดำเนินการตามบริบทแบบเป็นกลุ่มกับกลุ่มรายการในRecyclerView ซึ่งช่วยให้ผู้ใช้เลือกรายการหลายรายการและดําเนินการกับรายการทั้งหมดได้

ส่วนต่อไปนี้จะอธิบายการตั้งค่าที่จําเป็นสําหรับสถานการณ์แรก

เปิดใช้โหมดการดําเนินการตามบริบทสําหรับแต่ละมุมมอง

หากต้องการเรียกใช้โหมดการดำเนินการตามบริบทเฉพาะเมื่อผู้ใช้เลือกมุมมองที่เฉพาะเจาะจง ให้ทําดังนี้

  1. ใช้อินเทอร์เฟซ ActionMode.Callback ตามที่แสดงในตัวอย่างต่อไปนี้ ในเมธอดการเรียกกลับ คุณสามารถระบุการดำเนินการสำหรับแถบการดำเนินการตามบริบท ตอบสนองต่อเหตุการณ์การคลิกในรายการการดำเนินการ และจัดการเหตุการณ์วงจรอื่นๆ สำหรับโหมดการดำเนินการ

    Kotlin

        private val actionModeCallback = object : ActionMode.Callback {
            // Called when the action mode is created. startActionMode() is called.
            override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
                // Inflate a menu resource providing context menu items.
                val inflater: MenuInflater = mode.menuInflater
                inflater.inflate(R.menu.context_menu, menu)
                return true
            }
    
            // Called each time the action mode is shown. Always called after
            // onCreateActionMode, and might be called multiple times if the mode
            // is invalidated.
            override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
                return false // Return false if nothing is done
            }
    
            // Called when the user selects a contextual menu item.
            override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
                return when (item.itemId) {
                    R.id.menu_share -> {
                        shareCurrentItem()
                        mode.finish() // Action picked, so close the CAB.
                        true
                    }
                    else -> false
                }
            }
    
            // Called when the user exits the action mode.
            override fun onDestroyActionMode(mode: ActionMode) {
                actionMode = null
            }
        }
        

    Java

        private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
    
            // Called when the action mode is created. startActionMode() is called.
            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // Inflate a menu resource providing context menu items.
                MenuInflater inflater = mode.getMenuInflater();
                inflater.inflate(R.menu.context_menu, menu);
                return true;
            }
    
            // Called each time the action mode is shown. Always called after
            // onCreateActionMode, and might be called multiple times if the mode
            // is invalidated.
            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                return false; // Return false if nothing is done.
            }
    
            // Called when the user selects a contextual menu item.
            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
               switch (item.getItemId()) {
                    case R.id.menu_share:
                        shareCurrentItem();
                        mode.finish(); // Action picked, so close the CAB.
                        return true;
                    default:
                        return false;
                }
            }
    
            // Called when the user exits the action mode.
            @Override
            public void onDestroyActionMode(ActionMode mode) {
                actionMode = null;
            }
        };
        

    การเรียกกลับเหตุการณ์เหล่านี้เกือบจะเหมือนกับการเรียกกลับสําหรับเมนูตัวเลือก ยกเว้นว่าแต่ละรายการจะส่งออบเจ็กต์ ActionMode ที่เชื่อมโยงกับเหตุการณ์ด้วย คุณสามารถใช้ ActionMode API เพื่อทำการเปลี่ยนแปลงต่างๆ กับ CAB เช่น แก้ไขชื่อและคำบรรยายแทนด้วย setTitle() และ setSubtitle() ซึ่งมีประโยชน์ในการระบุจำนวนรายการที่เลือก

    ตัวอย่างก่อนหน้านี้ตั้งค่าตัวแปร actionMode เป็น null เมื่อโหมดการดำเนินการถูกทำลาย ในขั้นตอนถัดไป ให้ดูวิธีเริ่มต้นใช้งานและประโยชน์ของการบันทึกตัวแปรสมาชิกในกิจกรรมหรือส่วนต่างๆ

  2. เรียกใช้ startActionMode() เมื่อคุณต้องการแสดงแถบ เช่น เมื่อผู้ใช้แตะค้างไว้บนมุมมอง

    Kotlin

        someView.setOnLongClickListener { view ->
            // Called when the user performs a touch & hold on someView.
            when (actionMode) {
                null -> {
                    // Start the CAB using the ActionMode.Callback defined earlier.
                    actionMode = activity?.startActionMode(actionModeCallback)
                    view.isSelected = true
                    true
                }
                else -> false
            }
        }
        

    Java

        someView.setOnLongClickListener(new View.OnLongClickListener() {
            // Called when the user performs a touch & hold on someView.
            public boolean onLongClick(View view) {
                if (actionMode != null) {
                    return false;
                }
    
                // Start the CAB using the ActionMode.Callback defined earlier.
                actionMode = getActivity().startActionMode(actionModeCallback);
                view.setSelected(true);
                return true;
            }
        });
        

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

สร้างเมนูป๊อปอัป

รูปภาพแสดงเมนูป๊อปอัปในแอป Gmail ซึ่งยึดตำแหน่งไว้กับปุ่มรายการเพิ่มเติมที่ด้านขวาบน
รูปที่ 4 เมนูป๊อปอัปในแอป Gmail ที่ยึดอยู่กับปุ่มรายการเพิ่มเติมที่มุมขวาบน

PopupMenu คือเมนูแบบโมดัลที่ยึดอยู่กับ View โดยจะปรากฏใต้มุมมองหลักหากมีพื้นที่ หรือเหนือมุมมองหลักหากไม่มีพื้นที่ ซึ่งมีประโยชน์ในกรณีต่อไปนี้

  • การแสดงเมนูแบบรายการเพิ่มเติมสําหรับการดําเนินการที่เกี่ยวข้องกับเนื้อหาที่เฉพาะเจาะจง เช่น ส่วนหัวของอีเมล Gmail ดังที่แสดงในรูปที่ 4
  • ระบุส่วนที่สองของประโยคคำสั่ง เช่น ปุ่มที่มีข้อความระบุว่าเพิ่ม ซึ่งจะแสดงเมนูป๊อปอัปที่มีตัวเลือกเพิ่มต่างๆ
  • แสดงเมนูที่คล้ายกับ Spinner ซึ่งไม่เก็บการเลือกไว้อย่างถาวร

หากกำหนดเมนูใน XML คุณแสดงเมนูป๊อปอัปได้ดังนี้

  1. สร้าง PopupMenu ขึ้นมาทันทีด้วยตัวสร้าง ซึ่งจะรับแอปปัจจุบัน Context และ View ที่ยึดเมนูไว้
  2. ใช้ MenuInflater เพื่อขยายทรัพยากรเมนูเป็นออบเจ็กต์ Menu ที่ PopupMenu.getMenu() แสดง
  3. โทร PopupMenu.show()

ตัวอย่างเช่น ปุ่มที่แสดงเมนูป๊อปอัป

<ImageButton
    android:id="@+id/dropdown_menu"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@string/descr_overflow_button"
    android:src="@drawable/arrow_drop_down" />

จากนั้นกิจกรรมจะแสดงเมนูป๊อปอัปดังต่อไปนี้

Kotlin

findViewById<ImageButton>(R.id.dropdown_menu).setOnClickListener {
    val popup = PopupMenu(this, it)
    val inflater: MenuInflater = popup.menuInflater
    inflater.inflate(R.menu.actions, popup.menu)
    popup.show()
}

Java

findViewById(R.id.dropdown_menu).setOnClickListener(v -> {
    PopupMenu popup = new PopupMenu(this, v);
    popup.getMenuInflater().inflate(R.menu.actions, popup.getMenu());
    popup.show();
});

เมนูจะปิดเมื่อผู้ใช้เลือกรายการหรือแตะนอกพื้นที่เมนู คุณสามารถฟังเหตุการณ์การปิดโดยใช้ PopupMenu.OnDismissListener

จัดการเหตุการณ์การคลิก

หากต้องการดำเนินการเมื่อผู้ใช้เลือกรายการเมนู ให้ใช้ PopupMenu.OnMenuItemClickListener อินเทอร์เฟซและลงทะเบียนกับ PopupMenu โดยเรียกใช้ setOnMenuItemclickListener() เมื่อผู้ใช้เลือกรายการ ระบบจะเรียกใช้ callback ของ onMenuItemClick() ในอินเทอร์เฟซ

ดังที่แสดงในตัวอย่างต่อไปนี้

Kotlin

fun showMenu(v: View) {
    PopupMenu(this, v).apply {
        // MainActivity implements OnMenuItemClickListener.
        setOnMenuItemClickListener(this@MainActivity)
        inflate(R.menu.actions)
        show()
    }
}

override fun onMenuItemClick(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.archive -> {
            archive(item)
            true
        }
        R.id.delete -> {
            delete(item)
            true
        }
        else -> false
    }
}

Java

public void showMenu(View v) {
    PopupMenu popup = new PopupMenu(this, v);

    // This activity implements OnMenuItemClickListener.
    popup.setOnMenuItemClickListener(this);
    popup.inflate(R.menu.actions);
    popup.show();
}

@Override
public boolean onMenuItemClick(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.archive:
            archive(item);
            return true;
        case R.id.delete:
            delete(item);
            return true;
        default:
            return false;
    }
}

สร้างกลุ่มเมนู

กลุ่มเมนูคือคอลเล็กชันรายการเมนูที่มีลักษณะบางอย่างเหมือนกัน คุณจะทำสิ่งต่อไปนี้ได้เมื่อใช้กลุ่ม

  • แสดงหรือซ่อนรายการทั้งหมดโดยใช้ setGroupVisible()
  • เปิดหรือปิดใช้รายการทั้งหมดโดยใช้ setGroupEnabled()
  • ระบุว่าจะเลือกรายการทั้งหมดได้โดยใช้ setGroupCheckable() หรือไม่

คุณสามารถสร้างกลุ่มโดยการฝังองค์ประกอบ <item> ไว้ในองค์ประกอบ <group> ในทรัพยากรเมนู หรือระบุรหัสกลุ่มด้วยเมธอด add()

ต่อไปนี้คือตัวอย่างทรัพยากรเมนูที่มีกลุ่ม

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_save"
          android:icon="@drawable/menu_save"
          android:title="@string/menu_save" />
    <!-- menu group -->
    <group android:id="@+id/group_delete">
        <item android:id="@+id/menu_archive"
              android:title="@string/menu_archive" />
        <item android:id="@+id/menu_delete"
              android:title="@string/menu_delete" />
    </group>
</menu>

รายการที่อยู่ในกลุ่มจะปรากฏในระดับเดียวกับรายการแรก ซึ่งทั้ง 3 รายการในเมนูเป็นรายการพี่น้องกัน แต่คุณสามารถแก้ไขลักษณะของ 2 รายการในกลุ่มได้โดยอ้างอิงรหัสกลุ่มและใช้วิธีการก่อนหน้านี้ นอกจากนี้ ระบบจะไม่แยกรายการที่จัดกลุ่มไว้ ตัวอย่างเช่น หากคุณประกาศ android:showAsAction="ifRoom" สำหรับแต่ละรายการ รายการทั้ง 2 รายการจะปรากฏในแถบการดำเนินการหรือทั้ง 2 รายการจะปรากฏในแถบการดำเนินการเพิ่มเติม

ใช้รายการในเมนูที่เลือกได้

รูปที่ 5 เมนูย่อยที่มีรายการที่เลือกได้

เมนูอาจมีประโยชน์ในฐานะอินเทอร์เฟซสำหรับเปิดและปิดตัวเลือก โดยใช้ช่องทําเครื่องหมายสําหรับตัวเลือกแบบสแตนด์อโลน หรือปุ่มตัวเลือกสําหรับกลุ่มตัวเลือกที่เลือกร่วมกันไม่ได้ รูปที่ 5 แสดงเมนูย่อยที่มีรายการที่เลือกได้ด้วยปุ่มตัวเลือก

คุณสามารถกําหนดลักษณะการทำงานที่เลือกได้สําหรับรายการเมนูแต่ละรายการโดยใช้แอตทริบิวต์ android:checkable ในองค์ประกอบ <item> หรือสําหรับทั้งกลุ่มโดยใช้แอตทริบิวต์ android:checkableBehavior ในองค์ประกอบ <group> ตัวอย่างเช่น รายการทั้งหมดในกลุ่มเมนูนี้สามารถเลือกได้ด้วยปุ่มตัวเลือก

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item android:id="@+id/red"
              android:title="@string/red" />
        <item android:id="@+id/blue"
              android:title="@string/blue" />
    </group>
</menu>

แอตทริบิวต์ android:checkableBehavior ยอมรับค่าใดค่าหนึ่งต่อไปนี้

single
เลือกได้เพียงรายการเดียวจากกลุ่ม ซึ่งจะเป็นปุ่มตัวเลือก
all
เลือกรายการทั้งหมดได้ ซึ่งจะเป็นช่องทำเครื่องหมาย
none
เลือกรายการไม่ได้

คุณใช้สถานะ "เลือกไว้โดยค่าเริ่มต้น" กับรายการได้โดยใช้แอตทริบิวต์ android:checked ในองค์ประกอบ <item> และเปลี่ยนในโค้ดด้วยเมธอด setChecked()

เมื่อเลือกรายการที่เลือกได้ ระบบจะเรียกใช้เมธอดการเรียกกลับที่เลือกรายการที่เกี่ยวข้อง เช่น onOptionsItemSelected() ในส่วนนี้คุณตั้งค่าสถานะของช่องทําเครื่องหมายได้ เนื่องจากช่องทําเครื่องหมายหรือปุ่มตัวเลือกจะไม่เปลี่ยนสถานะโดยอัตโนมัติ คุณสามารถค้นหาสถานะปัจจุบันของรายการ (ตามที่เป็นอยู่ก่อนที่ผู้ใช้จะเลือก) ได้ด้วย isChecked() จากนั้นตั้งค่าสถานะ "เลือกแล้ว" ด้วย setChecked() ดังที่แสดงในตัวอย่างต่อไปนี้

Kotlin

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.vibrate, R.id.dont_vibrate -> {
            item.isChecked = !item.isChecked
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.vibrate:
        case R.id.dont_vibrate:
            if (item.isChecked()) item.setChecked(false);
            else item.setChecked(true);
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

หากคุณไม่ได้ตั้งค่าสถานะ "เลือกแล้ว" ด้วยวิธีนี้ สถานะที่มีให้เห็นของช่องทําเครื่องหมายหรือปุ่มตัวเลือกจะไม่เปลี่ยนแปลงเมื่อผู้ใช้เลือก เมื่อคุณตั้งค่าสถานะ กิจกรรมจะเก็บสถานะ "เลือกแล้ว" ของรายการไว้เพื่อให้ผู้ใช้เห็นสถานะ "เลือกแล้ว" ที่คุณตั้งไว้เมื่อเปิดเมนูในภายหลัง

เพิ่มรายการในเมนูตาม Intent

บางครั้งคุณต้องการให้รายการเมนูเปิดใช้งานกิจกรรมโดยใช้ Intent ไม่ว่าจะเป็นกิจกรรมในแอปหรือแอปอื่น เมื่อคุณทราบ Intent ที่ต้องการใช้และมีรายการเมนูที่เฉพาะเจาะจงซึ่งเริ่ม Intent ดังกล่าว คุณจะเรียกใช้ Intent นั้นได้ด้วย startActivity() ในระหว่างเมธอดการเรียกกลับเมื่อเลือกรายการที่เหมาะสม เช่น การเรียกกลับ onOptionsItemSelected()

อย่างไรก็ตาม หากคุณไม่แน่ใจว่าอุปกรณ์ของผู้ใช้มีแอปที่จัดการ Intent การเพิ่มรายการเมนูที่เรียกใช้ Intent อาจส่งผลให้รายการเมนูไม่ทํางาน เนื่องจาก Intent อาจไม่ได้รับการแก้ไขเป็นกิจกรรม ในการแก้ปัญหานี้ Android ให้คุณเพิ่มรายการเมนูลงในเมนูแบบไดนามิกได้เมื่อ Android พบกิจกรรมในอุปกรณ์ที่จัดการ Intent ของคุณ

หากต้องการเพิ่มรายการในเมนูตามกิจกรรมที่ใช้ได้ซึ่งยอมรับ Intent ให้ทําดังนี้

  1. กําหนด Intent ด้วยหมวดหมู่ CATEGORY_ALTERNATIVE หรือ CATEGORY_SELECTED_ALTERNATIVE หรือทั้ง 2 หมวดหมู่ พร้อมข้อกําหนดอื่นๆ
  2. โทรหา Menu.addIntentOptions() จากนั้น Android จะค้นหาแอปที่ดำเนินการตาม Intent ได้ แล้วเพิ่มแอปเหล่านั้นลงในเมนู

หากไม่มีแอปที่ติดตั้งไว้ซึ่งตรงกับเจตนา ระบบจะไม่เพิ่มรายการเมนู

ดังที่แสดงในตัวอย่างต่อไปนี้

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    super.onCreateOptionsMenu(menu)

    // Create an Intent that describes the requirements to fulfill, to be
    // included in the menu. The offering app must include a category value
    // of Intent.CATEGORY_ALTERNATIVE.
    val intent = Intent(null, dataUri).apply {
        addCategory(Intent.CATEGORY_ALTERNATIVE)
    }

    // Search and populate the menu with acceptable offering apps.
    menu.addIntentOptions(
            R.id.intent_group,  // Menu group to which new items are added.
            0,                  // Unique item ID (none).
            0,                  // Order for the items (none).
            this.componentName, // The current activity name.
            null,               // Specific items to place first (none).
            intent,             // Intent created above that describes the requirements.
            0,                  // Additional flags to control items (none).
            null)               // Array of MenuItems that correlate to specific items (none).

    return true
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu){
    super.onCreateOptionsMenu(menu);

    // Create an Intent that describes the requirements to fulfill, to be
    // included in the menu. The offering app must include a category value
    // of Intent.CATEGORY_ALTERNATIVE.
    Intent intent = new Intent(null, dataUri);
    intent.addCategory(Intent.CATEGORY_ALTERNATIVE);

    // Search and populate the menu with acceptable offering apps.
    menu.addIntentOptions(
         R.id.intent_group,         // Menu group to which new items are added.
         0,                         // Unique item ID (none).
         0,                         // Order for the items (none).
         this.getComponentName(),   // The current activity name.
         null,                      // Specific items to place first (none).
         intent,                    // Intent created above that describes the requirements.
         0,                         // Additional flags to control items (none).
         null);                     // Array of MenuItems that correlate to specific items (none).

    return true;
}

สําหรับกิจกรรมแต่ละรายการที่พบซึ่งมีตัวกรอง Intent ที่ตรงกับ Intent ที่กําหนด ระบบจะเพิ่มรายการเมนูโดยใช้ค่าใน android:label ของตัวกรอง Intent เป็นชื่อรายการเมนู และไอคอนแอปเป็นไอคอนรายการเมนู เมธอด addIntentOptions() จะแสดงจํานวนรายการเมนูที่เพิ่ม

อนุญาตให้เพิ่มกิจกรรมของคุณลงในเมนูอื่นๆ

คุณสามารถเสนอบริการของกิจกรรมให้กับแอปอื่นๆ เพื่อให้แอปของคุณรวมอยู่ในเมนูของแอปอื่นๆ ได้ ซึ่งจะกลับบทบาทที่อธิบายไว้ก่อนหน้านี้

หากต้องการให้รวมอยู่ในเมนูของแอปอื่นๆ ให้กำหนดตัวกรอง Intent ตามปกติ แต่ใส่ค่า CATEGORY_ALTERNATIVE หรือ CATEGORY_SELECTED_ALTERNATIVE หรือทั้ง 2 ค่าสำหรับหมวดหมู่ตัวกรอง Intent ดังที่แสดงในตัวอย่างต่อไปนี้

<intent-filter label="@string/resize_image">
    ...
    <category android:name="android.intent.category.ALTERNATIVE" />
    <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
    ...
</intent-filter>

อ่านเพิ่มเติมเกี่ยวกับการเขียนตัวกรอง Intent ในIntent และตัวกรอง Intent