เมนูเป็นคอมโพเนนต์อินเทอร์เฟซผู้ใช้ที่พบบ่อยในแอปหลายประเภท หากต้องการมอบประสบการณ์การใช้งานที่คุ้นเคยและสอดคล้องกัน ให้ใช้ MenuAPI เพื่อแสดงการดำเนินการของผู้ใช้และตัวเลือกอื่นๆ ในกิจกรรมของคุณ
เอกสารนี้แสดงวิธีสร้างเมนูหรือการนำเสนอการดำเนินการพื้นฐาน 3 ประเภทใน Android ทุกเวอร์ชัน
- เมนูตัวเลือกและแถบแอป
- เมนูตัวเลือกคือคอลเล็กชันหลักของรายการในเมนูสำหรับกิจกรรม
ซึ่งเป็นที่ที่คุณวางการกระทำที่มีผลกระทบต่อแอปในระดับโลก เช่น "ค้นหา" "เขียนอีเมล" และ "การตั้งค่า"
ดูส่วนสร้างเมนูตัวเลือก
- เมนูตามบริบทและโหมดการดำเนินการตามบริบท
- เมนูตามบริบทคือเมนูแบบลอย
ซึ่งจะปรากฏเมื่อผู้ใช้แตะองค์ประกอบค้างไว้ ซึ่งจะ
แสดงการดำเนินการที่มีผลต่อเนื้อหาหรือกรอบบริบทที่เลือก
โหมดการดำเนินการตามบริบทจะแสดงรายการการดำเนินการที่ ส่งผลต่อเนื้อหาที่เลือกในแถบที่ด้านบนของหน้าจอ และช่วยให้ ผู้ใช้เลือกหลายรายการได้
ดูส่วนสร้างเมนูตามบริบท
- เมนูป๊อปอัป
- เมนูแบบป๊อปอัปจะแสดงรายการแนวตั้งที่ยึดกับ
มุมมองที่เรียกใช้เมนู เหมาะสำหรับการแสดงการดำเนินการเพิ่มเติม
ที่เกี่ยวข้องกับเนื้อหาที่เฉพาะเจาะจง หรือเพื่อแสดงตัวเลือกสำหรับส่วนที่ 2
ของคำสั่ง การดำเนินการในเมนูป๊อปอัปจะไม่ส่งผลต่อเนื้อหาที่เกี่ยวข้องโดยตรง ซึ่งเป็นสิ่งที่การดำเนินการตามบริบทมีไว้ แต่เมนูป๊อปอัปมีไว้สำหรับการดำเนินการเพิ่มเติมที่เกี่ยวข้องกับภูมิภาคของเนื้อหาในกิจกรรมของคุณ
ดูส่วนสร้างเมนูป๊อปอัป
กำหนดเมนูใน XML
สำหรับเมนูทุกประเภท Android มีรูปแบบ XML มาตรฐานเพื่อกำหนดรายการเมนู
แทนที่จะสร้างเมนูในโค้ดของกิจกรรม ให้กำหนดเมนูและ
รายการทั้งหมดใน XML
ทรัพยากรเมนู จากนั้นคุณจะ
ขยายทรัพยากรเมนูได้โดยโหลดเป็นออบเจ็กต์ Menu
ในกิจกรรมหรือ Fragment
การใช้ทรัพยากรเมนูเป็นแนวทางปฏิบัติแนะนำด้วยเหตุผลต่อไปนี้
- ซึ่งจะช่วยให้เห็นภาพโครงสร้างเมนูใน 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- การอ้างอิงถึง Drawable ที่จะใช้เป็นไอคอนของรายการ
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 คือที่ที่คุณใส่ การดำเนินการและตัวเลือกอื่นๆ ที่เกี่ยวข้องกับบริบทกิจกรรมปัจจุบัน เช่น "ค้นหา" "เขียนอีเมล" และ "การตั้งค่า"
คุณสามารถประกาศรายการสำหรับเมนูตัวเลือกจากคลาสย่อย Activity หรือคลาสย่อย Fragment หากทั้งกิจกรรมและ Fragment ประกาศรายการสำหรับเมนูตัวเลือก ระบบจะรวมรายการไว้ใน UI รายการของกิจกรรมจะปรากฏก่อน ตามด้วยรายการของแต่ละ Fragment ตามลำดับที่เพิ่ม Fragment ลงในกิจกรรม หากจำเป็น คุณสามารถจัดเรียงรายการเมนูใหม่ได้โดยใช้แอตทริบิวต์ android:orderInCategory ในแต่ละ <item> ที่ต้องการย้าย
หากต้องการระบุเมนูตัวเลือกสำหรับกิจกรรม ให้ลบล้าง
onCreateOptionsMenu()
Fragment จะมี
onCreateOptionsMenu()
การเรียกกลับของตัวเอง ในวิธีนี้ คุณสามารถขยายทรัพยากรเมนูที่กำหนดไว้ใน XML เป็น Menu ที่ระบุไว้ใน
การเรียกกลับ ตัวอย่างต่อไปนี้แสดงให้เห็นถึงการดำเนินการนี้
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() การใช้งานเริ่มต้นจะแสดงผลเป็น
false
หากกิจกรรมมี Fragment ระบบจะเรียกใช้
onOptionsItemSelected() สำหรับกิจกรรมก่อน จากนั้นจะเรียกใช้สำหรับแต่ละ Fragment
ตามลำดับการเพิ่ม Fragment จนกว่าจะมี Fragment ใด Fragment หนึ่งแสดงผล true หรือ
เรียกใช้ Fragment ทั้งหมด
เปลี่ยนรายการในเมนูขณะรันไทม์
หลังจากที่ระบบเรียกใช้ onCreateOptionsMenu() แล้ว ระบบจะเก็บ
อินสแตนซ์ของ Menu ที่คุณป้อนไว้และจะไม่เรียกใช้
onCreateOptionsMenu() อีก เว้นแต่เมนูจะใช้ไม่ได้
อย่างไรก็ตาม ให้ใช้ onCreateOptionsMenu() เพื่อสร้างสถานะเมนูเริ่มต้นเท่านั้น
และอย่าใช้เพื่อทำการเปลี่ยนแปลงในระหว่างวงจรกิจกรรม
หากต้องการแก้ไขเมนูตัวเลือกตามเหตุการณ์ที่เกิดขึ้นในวงจรกิจกรรม คุณสามารถทำได้ในเมธอด onPrepareOptionsMenu() วิธีนี้จะส่งออบเจ็กต์ Menu ให้คุณตามที่ออบเจ็กต์นั้นมีอยู่
ในปัจจุบัน เพื่อให้คุณแก้ไขได้ เช่น เพิ่ม นำออก หรือปิดใช้รายการ
นอกจากนี้ Fragment ยังมี
onPrepareOptionsMenu()
การเรียกกลับด้วย
ระบบจะถือว่าเมนูตัวเลือกเปิดอยู่เสมอเมื่อแสดงรายการในเมนูในแถบแอป เมื่อเกิดเหตุการณ์และคุณต้องการอัปเดตเมนู ให้เรียกใช้
invalidateOptionsMenu()
เพื่อขอให้ระบบเรียกใช้ onPrepareOptionsMenu()
สร้างเมนูตามบริบท
เมนูตามบริบทจะมีการดำเนินการที่ส่งผลต่อรายการหรือบริบท
เฟรมที่เฉพาะเจาะจงใน 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ช่วยให้คุณขยายเมนูตามบริบทจากทรัพยากรเมนูได้ พารามิเตอร์ของเมธอด Callback ประกอบด้วย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หาก คุณไม่ได้จัดการรายการเมนู ให้ส่งรายการเมนูไปยังการใช้งานของคลาสแม่ หากกิจกรรมมี Fragment กิจกรรมจะได้รับการเรียกกลับนี้ก่อน การเรียกคลาสแม่เมื่อไม่มีการจัดการ ระบบจะ ส่งเหตุการณ์ไปยังเมธอดเรียกกลับที่เกี่ยวข้องในแต่ละ Fragment ทีละรายการ ตามลำดับการเพิ่มแต่ละ Fragment จนกว่าจะมีการส่งคืนtrueหรือfalseการติดตั้งใช้งานเริ่มต้นสำหรับActivityและandroid.app.Fragmentจะแสดงผลfalseดังนั้นให้เรียกคลาสแม่เสมอเมื่อไม่มีการจัดการ
ใช้โหมดการดำเนินการตามบริบท
โหมดการดำเนินการตามบริบทคือการติดตั้งใช้งานระบบของ
ActionMode ที่มุ่งเน้นการโต้ตอบของผู้ใช้ไปที่การดำเนินการตามบริบท เมื่อผู้ใช้เปิดใช้โหมดนี้โดยการเลือกรายการหนึ่งๆ แถบการทำงานตามบริบทจะปรากฏที่ด้านบนของหน้าจอเพื่อแสดงการดำเนินการที่ผู้ใช้ทำกับรายการที่เลือกได้
ขณะที่เปิดใช้โหมดนี้
ผู้ใช้จะเลือกหลายรายการได้หากแอปของคุณรองรับ และสามารถยกเลิกการเลือก
รายการและไปยังส่วนต่างๆ ในกิจกรรมต่อได้ โหมดการดำเนินการจะปิดอยู่
และแถบการดำเนินการตามบริบทจะหายไปเมื่อผู้ใช้ยกเลิกการเลือกรายการทั้งหมด
แตะปุ่มย้อนกลับ หรือแตะการดำเนินการเสร็จสิ้นทางด้านซ้ายของ
แถบ
สำหรับมุมมองที่ให้การดำเนินการตามบริบท โดยปกติคุณจะเรียกใช้โหมดการดำเนินการตามบริบทเมื่อเกิดเหตุการณ์ใดเหตุการณ์หนึ่งหรือทั้ง 2 เหตุการณ์ต่อไปนี้
- ผู้ใช้แตะมุมมองค้างไว้
- ผู้ใช้เลือกช่องทําเครื่องหมายหรือคอมโพเนนต์ UI ที่คล้ายกันภายในมุมมอง
วิธีที่แอปเรียกใช้โหมดการดำเนินการตามบริบทและกำหนดลักษณะการทำงานของการดำเนินการแต่ละอย่างจะขึ้นอยู่กับการออกแบบของคุณ โดยมี 2 รูปแบบดังนี้
- สำหรับการดำเนินการตามบริบทในมุมมองแต่ละรายการที่กำหนดเอง
- สำหรับการดำเนินการตามบริบทแบบเป็นชุดในกลุ่มรายการใน
RecyclerViewซึ่งช่วยให้ผู้ใช้เลือกหลายรายการและ ดำเนินการกับรายการทั้งหมดได้
ส่วนต่อไปนี้จะอธิบายการตั้งค่าที่จำเป็นสำหรับสถานการณ์แรก
เปิดใช้โหมดการดำเนินการตามบริบทสำหรับแต่ละมุมมอง
หากต้องการเรียกใช้โหมดการดำเนินการตามบริบทเฉพาะเมื่อผู้ใช้เลือกมุมมองที่เฉพาะเจาะจง ให้ทำดังนี้
- ใช้
ActionMode.Callbackอินเทอร์เฟซตามที่แสดงใน ตัวอย่างต่อไปนี้ ในเมธอด 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ที่เชื่อมโยงกับเหตุการณ์ด้วย คุณใช้ActionModeAPI เพื่อทำการเปลี่ยนแปลงต่างๆ กับ CAB ได้ เช่น การแก้ไขชื่อและคำบรรยายด้วยsetTitle()และsetSubtitle()ซึ่งมีประโยชน์ในการระบุจำนวนรายการที่เลือกตัวอย่างก่อนหน้าจะตั้งค่าตัวแปร
actionModeเป็นnullเมื่อทำลายโหมดการดำเนินการ ในขั้นตอนถัดไป ให้ดู วิธีเริ่มต้นใช้งานและวิธีที่การบันทึกตัวแปรสมาชิกในกิจกรรมหรือ Fragment จะเป็นประโยชน์ - Call
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ใหม่หากอินสแตนซ์นั้นทำงานอยู่แล้ว โดยการตรวจสอบว่าสมาชิกเป็น Null หรือไม่ก่อนที่จะเริ่มโหมดการดำเนินการ
สร้างเมนูป๊อปอัป
PopupMenu
คือเมนูแบบโมดอลที่ยึดกับ View โดยจะปรากฏใต้ Anchor
View หากมีพื้นที่ หรือเหนือ View หากไม่มีพื้นที่ ซึ่งมีประโยชน์สำหรับ
สิ่งต่อไปนี้
- การแสดงเมนูสไตล์ล้นสำหรับดำเนินการที่เกี่ยวข้องกับ เนื้อหาที่เฉพาะเจาะจง เช่น ส่วนหัวของอีเมลใน Gmail ดังที่แสดงในรูปที่ 4
- การระบุส่วนที่ 2 ของประโยคคำสั่ง เช่น ปุ่มที่ทำเครื่องหมายว่า เพิ่ม ซึ่งจะสร้างเมนูป๊อปอัปที่มีตัวเลือกเพิ่ม ต่างๆ
- การแสดงเมนูที่คล้ายกับ
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()
เมื่อผู้ใช้เลือกรายการ ระบบจะเรียกใช้แฮนเดิล
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- เลือกได้เพียง 1 รายการจากกลุ่ม ซึ่งจะทำให้เกิดปุ่มตัวเลือก
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 ด้วย
startActivity()
ในระหว่างเมธอด Callback on-item-selected ที่เหมาะสมได้ เช่น Callback onOptionsItemSelected()
อย่างไรก็ตาม หากคุณไม่แน่ใจว่าอุปกรณ์ของผู้ใช้มีแอปที่ จัดการ Intent หรือไม่ การเพิ่มรายการเมนูที่เรียกใช้ Intent อาจส่งผลให้ รายการเมนูใช้งานไม่ได้ เนื่องจาก Intent อาจไม่สามารถแก้ไขเป็นกิจกรรมได้ Android จึงให้คุณเพิ่มรายการเมนูลงในเมนูแบบไดนามิกได้เมื่อ Android พบกิจกรรมในอุปกรณ์ที่จัดการ 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