เมนูเป็นคอมโพเนนต์อินเทอร์เฟซผู้ใช้ทั่วไปในแอปหลายประเภท หากต้องการให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่คุ้นเคยและสอดคล้องกัน ให้ใช้ Menu
API เพื่อแสดงการดําเนินการของผู้ใช้และตัวเลือกอื่นๆ ในกิจกรรม
เอกสารนี้แสดงวิธีสร้างเมนูหรือการแสดงผลการดำเนินการพื้นฐาน 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 ชีต](https://developer.android.com/static/images/training/appbar/appbar_sheets_2x.png?authuser=3&hl=th)
คุณสามารถประกาศรายการสำหรับเมนูตัวเลือกจากคลาสย่อยของ
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()
สร้างเมนูตามบริบท
![รูปภาพแสดงเมนูตามบริบทแบบลอย](https://developer.android.com/static/develop/ui/views/images/context_menu_no_icons.png?authuser=3&hl=th)
เมนูตามบริบทมีการดำเนินการที่ส่งผลต่อรายการหรือเฟรมบริบทที่เฉพาะเจาะจงใน UI คุณระบุเมนูตามบริบทสำหรับมุมมองใดก็ได้ แต่มักใช้กับรายการในRecylerView
หรือคอลเล็กชันมุมมองอื่นๆ ที่ผู้ใช้สามารถดำเนินการกับแต่ละรายการได้โดยตรง
การดำเนินการตามบริบทมี 2 วิธีดังนี้
- ในเมนูตามบริบทแบบลอย เมนูจะปรากฏเป็นรายการรายการเมนูที่ลอยอยู่ ซึ่งคล้ายกับกล่องโต้ตอบ เมื่อผู้ใช้แตะและกดค้างไว้ที่มุมมองที่ประกาศรองรับเมนูตามบริบท ผู้ใช้สามารถดําเนินการตามบริบทกับรายการได้ครั้งละ 1 รายการ
- ในโหมดการดำเนินการตามบริบท โหมดนี้เป็นการใช้งาน
ActionMode
ของระบบที่แสดงแถบการดำเนินการตามบริบทหรือ CAB ที่ด้านบนของหน้าจอพร้อมรายการการดำเนินการที่ส่งผลต่อรายการที่เลือก เมื่อโหมดนี้ทำงานอยู่ ผู้ใช้จะดำเนินการกับหลายรายการพร้อมกันได้ หากแอปของคุณรองรับ
หมายเหตุ: เมนูตามบริบทไม่รองรับแป้นพิมพ์ลัดของรายการและไอคอนของรายการ
สร้างเมนูตามบริบทแบบลอย
หากต้องการแสดงเมนูตามบริบทแบบลอย ให้ทําดังนี้
- ลงทะเบียน
View
ที่เชื่อมโยงกับเมนูตามบริบทโดยเรียกใช้registerForContextMenu()
และส่งView
หากกิจกรรมใช้
RecyclerView
และคุณต้องการให้แต่ละรายการแสดงเมนูตามบริบทเดียวกัน ให้ลงทะเบียนรายการทั้งหมดสำหรับเมนูตามบริบทโดยส่งRecyclerView
ไปยังregisterForContextMenu()
- ใช้วิธี
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
ที่แสดงข้อมูลเพิ่มเติมเกี่ยวกับรายการที่เลือก หากกิจกรรมมีมุมมองหลายมุมมองที่แต่ละมุมมองมีเมนูบริบทต่างกัน คุณอาจใช้พารามิเตอร์เหล่านี้เพื่อระบุเมนูบริบทที่จะขยาย ติดตั้งใช้งาน
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
ซึ่งช่วยให้ผู้ใช้เลือกรายการหลายรายการและดําเนินการกับรายการทั้งหมดได้
ส่วนต่อไปนี้จะอธิบายการตั้งค่าที่จําเป็นสําหรับสถานการณ์แรก
เปิดใช้โหมดการดําเนินการตามบริบทสําหรับแต่ละมุมมอง
หากต้องการเรียกใช้โหมดการดำเนินการตามบริบทเฉพาะเมื่อผู้ใช้เลือกมุมมองที่เฉพาะเจาะจง ให้ทําดังนี้
- ใช้อินเทอร์เฟซ
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
เมื่อโหมดการดำเนินการถูกทำลาย ในขั้นตอนถัดไป ให้ดูวิธีเริ่มต้นใช้งานและประโยชน์ของการบันทึกตัวแปรสมาชิกในกิจกรรมหรือส่วนต่างๆ - เรียกใช้
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 ซึ่งยึดตำแหน่งไว้กับปุ่มรายการเพิ่มเติมที่ด้านขวาบน](https://developer.android.com/static/images/ui/popupmenu.png?authuser=3&hl=th)
PopupMenu
คือเมนูแบบโมดัลที่ยึดอยู่กับ View
โดยจะปรากฏใต้มุมมองหลักหากมีพื้นที่ หรือเหนือมุมมองหลักหากไม่มีพื้นที่ ซึ่งมีประโยชน์ในกรณีต่อไปนี้
- การแสดงเมนูแบบรายการเพิ่มเติมสําหรับการดําเนินการที่เกี่ยวข้องกับเนื้อหาที่เฉพาะเจาะจง เช่น ส่วนหัวของอีเมล Gmail ดังที่แสดงในรูปที่ 4
- ระบุส่วนที่สองของประโยคคำสั่ง เช่น ปุ่มที่มีข้อความระบุว่าเพิ่ม ซึ่งจะแสดงเมนูป๊อปอัปที่มีตัวเลือกเพิ่มต่างๆ
- แสดงเมนูที่คล้ายกับ
Spinner
ซึ่งไม่เก็บการเลือกไว้อย่างถาวร
หากกำหนดเมนูใน XML คุณแสดงเมนูป๊อปอัปได้ดังนี้
- สร้าง
PopupMenu
ขึ้นมาทันทีด้วยตัวสร้าง ซึ่งจะรับแอปปัจจุบันContext
และView
ที่ยึดเมนูไว้ - ใช้
MenuInflater
เพื่อขยายทรัพยากรเมนูเป็นออบเจ็กต์Menu
ที่PopupMenu.getMenu()
แสดง - โทร
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 แสดงเมนูย่อยที่มีรายการที่เลือกได้ด้วยปุ่มตัวเลือก
คุณสามารถกําหนดลักษณะการทำงานที่เลือกได้สําหรับรายการเมนูแต่ละรายการโดยใช้แอตทริบิวต์ 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 ให้ทําดังนี้
- กําหนด Intent ด้วยหมวดหมู่
CATEGORY_ALTERNATIVE
หรือCATEGORY_SELECTED_ALTERNATIVE
หรือทั้ง 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