หัวข้อสำคัญ

ลองใช้วิธีแบบ Compose
Jetpack Compose เป็นชุดเครื่องมือ UI ที่แนะนำสำหรับ Android ดูวิธีใช้การลากและวางใน Compose

ส่วนต่อไปนี้จะอธิบายแนวคิดหลักบางประการสำหรับกระบวนการลากและวาง

กระบวนการลากและวาง

กระบวนการลากและวางมี 4 ขั้นตอนหรือสถานะ ได้แก่ เริ่มต้น กำลังดำเนินการต่อ วาง และสิ้นสุด

เริ่มต้นแล้ว

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

  • ข้อมูลที่จะลาก
  • Callback สำหรับการวาดเงาการลาก
  • ข้อมูลเมตาที่อธิบายข้อมูลที่ลาก
  • ระบบจะตอบกลับด้วยการเรียกกลับไปยังแอปพลิเคชันของคุณเพื่อรับเงาการลาก จากนั้นระบบจะแสดงเงาการลากบนอุปกรณ์
  • จากนั้นระบบจะส่งเหตุการณ์การลากที่มีประเภทการดำเนินการ ACTION_DRAG_STARTED ไปยัง Listener เหตุการณ์การลากของออบเจ็กต์ View ทั้งหมดในเลย์เอาต์ปัจจุบัน Listener เหตุการณ์การลากต้องแสดงผล true เพื่อรับเหตุการณ์การลากต่อไป ซึ่งรวมถึงเหตุการณ์การวางที่อาจเกิดขึ้น การดำเนินการนี้จะลงทะเบียน Listener กับระบบ เฉพาะ Listener ที่ลงทะเบียนแล้วเท่านั้นที่จะได้รับเหตุการณ์การลากต่อไป นอกจากนี้ Listener ยังสามารถเปลี่ยนลักษณะที่ปรากฏของออบเจ็กต์ View เป้าหมายการวางเพื่อแสดงว่ามุมมองยอมรับเหตุการณ์การวางได้
  • หาก Listener เหตุการณ์การลากแสดงผล false Listener จะไม่ได้รับเหตุการณ์ การลากสำหรับการดำเนินการปัจจุบันจนกว่าระบบจะส่งเหตุการณ์การลาก ที่มีประเภทการดำเนินการ ACTION_DRAG_ENDED การแสดงผล false จะบอกให้ระบบทราบว่า Listener ไม่สนใจการดำเนินการลากและวางและไม่ต้องการยอมรับข้อมูลที่ลาก
กำลังดำเนินการต่อ
ผู้ใช้ลากต่อไป เมื่อเงาการลากตัดกับกรอบล้อมรอบของเป้าหมายการวาง ระบบจะส่งเหตุการณ์การลากอย่างน้อย 1 เหตุการณ์ไปยัง Listener เหตุการณ์การลากของเป้าหมาย Listener อาจเปลี่ยนลักษณะที่ปรากฏของ View เป้าหมายการวางเพื่อตอบสนองต่อเหตุการณ์ ตัวอย่างเช่น หากเหตุการณ์ ระบุว่าเงาการลากเข้าสู่กรอบล้อมรอบของเป้าหมายการวาง ประเภทการดำเนินการ ACTION_DRAG_ENTERED Listener สามารถตอบสนองด้วยการไฮไลต์ View
วางแล้ว
ผู้ใช้ปล่อยเงาการลากภายในกรอบล้อมรอบของเป้าหมายการวาง ระบบจะส่งเหตุการณ์การลากที่มี action type ACTION_DROP ไปยัง Listener ของเป้าหมายการวาง ออบเจ็กต์เหตุการณ์การลากมีข้อมูลที่ส่งไปยังระบบในการเรียกใช้ startDragAndDrop() ซึ่งเริ่มการดำเนินการ ระบบคาดหวังให้ Listener แสดงผลบูลีน true หาก Listener ประมวลผลข้อมูลที่วางสำเร็จ : ขั้นตอนนี้จะเกิดขึ้นก็ต่อเมื่อผู้ใช้วางเงาการลากภายในกรอบล้อมรอบของ View ที่ลงทะเบียน Listener เพื่อรับเหตุการณ์การลาก (เป้าหมายการวาง) หากผู้ใช้ปล่อยเงาการลากในสถานการณ์อื่นๆ ระบบจะไม่ส่งเหตุการณ์การลาก ACTION_DROP
สิ้นสุดแล้ว

หลังจากผู้ใช้ปล่อยเงาการลากและหลังจากที่ระบบส่ง

เหตุการณ์การลากที่มีประเภทการดำเนินการ ACTION_DROP (หากจำเป็น) ระบบจะส่งเหตุการณ์การลากที่มีประเภทการดำเนินการ ACTION_DRAG_ENDED เพื่อระบุว่าการดำเนินการลากและวางสิ้นสุดลงแล้ว การดำเนินการนี้จะเกิดขึ้นไม่ว่าผู้ใช้จะปล่อยเงาการลากไว้ที่ใดก็ตาม ระบบจะส่งเหตุการณ์ไปยัง Listener ทุกรายการที่ลงทะเบียนเพื่อรับเหตุการณ์การลาก แม้ว่า Listener จะได้รับเหตุการณ์ ACTION_DROP ด้วยก็ตาม

เราอธิบายแต่ละขั้นตอนเหล่านี้โดยละเอียดเพิ่มเติมในส่วนที่ชื่อว่า การดำเนินการลากและวาง

เหตุการณ์การลาก

ระบบจะส่งเหตุการณ์การลากในรูปแบบออบเจ็กต์ DragEvent ซึ่งมีประเภทการดำเนินการที่อธิบายสิ่งที่เกิดขึ้นในกระบวนการลากและวาง ออบเจ็กต์อาจมีข้อมูลอื่นๆ ด้วย ทั้งนี้ขึ้นอยู่กับประเภทการดำเนินการ

Listener เหตุการณ์การลากจะได้รับออบเจ็กต์ DragEvent หากต้องการรับประเภทการดำเนินการ Listener จะเรียกใช้ DragEvent.getAction() ค่าที่เป็นไปได้ 6 ค่ากำหนดโดยค่าคงที่ในคลาส DragEvent ซึ่งอธิบายไว้ในตารางที่ 1

ตารางที่ 1 ประเภทการดำเนินการ DragEvent

ประเภทการดำเนินการ ความหมาย
ACTION_DRAG_STARTED แอปพลิเคชันเรียกใช้ startDragAndDrop() และได้รับ เงาการลาก หาก Listener ต้องการรับเหตุการณ์การลากสำหรับการดำเนินการนี้ต่อไป Listener จะต้องแสดงผลบูลีน true ไปยังระบบ
ACTION_DRAG_ENTERED เงาการลากเข้าสู่กรอบล้อมรอบของ Listener เหตุการณ์การลาก View นี่คือประเภทการดำเนินการของเหตุการณ์แรกที่ Listener ได้รับเมื่อเงาการลากเข้าสู่กรอบล้อมรอบ
ACTION_DRAG_LOCATION หลังจากเหตุการณ์ ACTION_DRAG_ENTERED เงาการลากยังคงอยู่ ภายในกรอบล้อมรอบของ Listener เหตุการณ์การลาก View
ACTION_DRAG_EXITED หลังจาก ACTION_DRAG_ENTERED และเหตุการณ์ ACTION_DRAG_LOCATION อย่างน้อย 1 เหตุการณ์ เงาการลากจะเคลื่อนที่ ออกจากกรอบล้อมรอบของ View ของ Listener เหตุการณ์การลาก
ACTION_DROP เงาการลากปล่อยเหนือ View ของ Listener เหตุการณ์การลาก ระบบจะส่งประเภทการดำเนินการนี้ไปยัง View Listener ของออบเจ็กต์ ก็ต่อเมื่อ Listener แสดงผลบูลีน true เพื่อตอบสนองต่อ ACTION_DRAG_STARTED เหตุการณ์การลาก ระบบจะไม่ส่งประเภทการดำเนินการนี้หากผู้ใช้ปล่อยเงาการลากเหนือ View ที่ไม่ได้ลงทะเบียน Listener หรือหากผู้ใช้ปล่อยเงาการลากเหนือสิ่งที่ไม่ใช่ส่วนหนึ่งของเลย์เอาต์ปัจจุบัน

Listener จะแสดงผลบูลีน true หากประมวลผลการวางสำเร็จ ไม่เช่นนั้น Listener จะต้องแสดงผล false

ACTION_DRAG_ENDED ระบบกำลังสิ้นสุดการดำเนินการลากและวาง ประเภทการดำเนินการนี้ อาจไม่ได้นำหน้าด้วยเหตุการณ์ ACTION_DROP เสมอไป หาก ระบบส่ง ACTION_DROP การได้รับ ACTION_DRAG_ENDED ประเภทการดำเนินการไม่ได้หมายความว่า การวางสำเร็จ Listener ต้องเรียกใช้ getResult(), ตามที่แสดงใน ตารางที่ 2 เพื่อรับค่าที่ แสดงผลเพื่อตอบสนองต่อ ACTION_DROP หากระบบไม่ส่งเหตุการณ์ ACTION_DROP แล้ว getResult() จะแสดงผล false

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

ตารางที่ 2 ข้อมูล DragEvent ที่ใช้ได้ตามประเภทการดำเนินการ

getAction()
value
getClipDescription()
value
getLocalState()
value
getX()
value
getY()
value
getClipData()
value
getResult()
value
ACTION_DRAG_STARTED ✓ ✓        
ACTION_DRAG_ENTERED ✓ ✓        
ACTION_DRAG_LOCATION ✓ ✓ ✓ ✓    
ACTION_DRAG_EXITED ✓ ✓        
ACTION_DROP ✓ ✓ ✓ ✓ ✓  
ACTION_DRAG_ENDED   ✓       ✓

เมธอด DragEvent ได้แก่ getAction(), describeContents(), writeToParcel(), และ toString() จะแสดงผลข้อมูลที่ใช้ได้เสมอ

หากเมธอดไม่มีข้อมูลที่ใช้ได้สำหรับประเภทการดำเนินการหนึ่งๆ เมธอดจะแสดงผล null หรือ 0 ทั้งนี้ขึ้นอยู่กับประเภทผลลัพธ์

เงาการลาก

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

รูปภาพนี้เรียกว่า เงาการลาก คุณสร้างเงาการลากด้วยเมธอดที่ประกาศไว้สำหรับ ออบเจ็กต์ View.DragShadowBuilder คุณส่ง Builder ไปยังระบบเมื่อเริ่มการดำเนินการลากและวางโดยใช้ startDragAndDrop() ระบบจะเรียกใช้เมธอด Callback ที่คุณกำหนดไว้ใน View.DragShadowBuilder เพื่อรับเงาการลาก ซึ่งเป็นส่วนหนึ่งของการตอบสนองต่อ startDragAndDrop()

คลาส View.DragShadowBuilder มีคอนสตรักเตอร์ 2 รายการ ดังนี้

View.DragShadowBuilder(View)

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

หากใช้คอนสตรักเตอร์นี้ คุณไม่จำเป็นต้องขยาย View.DragShadowBuilder หรือลบล้างเมธอดของคอนสตรักเตอร์ โดยค่าเริ่มต้น คุณจะได้รับเงาการลากที่มีลักษณะที่ปรากฏเหมือนกับ View ที่คุณส่งเป็นอาร์กิวเมนต์ โดยอยู่ตรงกลางใต้ตำแหน่งที่ผู้ใช้แตะหน้าจอ

View.DragShadowBuilder()

หากใช้คอนสตรักเตอร์นี้ ออบเจ็กต์ View จะไม่พร้อมใช้งานในออบเจ็กต์ View.DragShadowBuilder ระบบจะตั้งค่าฟิลด์เป็น null คุณต้องขยาย View.DragShadowBuilder และลบล้างเมธอดของคอนสตรักเตอร์ ไม่เช่นนั้นคุณจะได้รับเงาการลากที่มองไม่เห็น ระบบจะไม่แสดงข้อผิดพลาด

คลาส View.DragShadowBuilder มี 2 เมธอดที่ทำงานร่วมกันเพื่อสร้างเงาการลาก ดังนี้

onProvideShadowMetrics()

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

outShadowSize: ออบเจ็กต์ Point ความกว้างของเงาการลากจะอยู่ใน x และความสูงจะอยู่ใน y

outShadowTouchPoint: ออบเจ็กต์ Point จุดสัมผัสคือตำแหน่งภายในเงาการลากที่ต้องอยู่ใต้ปลายนิ้วของผู้ใช้ระหว่างการลาก ตำแหน่ง X จะอยู่ใน x และตำแหน่ง Y จะอยู่ใน y

onDrawShadow()

ระบบจะเรียกใช้ onDrawShadow() ทันทีหลังจากเรียกใช้ onProvideShadowMetrics() เพื่อสร้างเงาการลาก เมธอดนี้มีอาร์กิวเมนต์เดียวคือออบเจ็กต์ Canvas ที่ระบบสร้างขึ้นจากพารามิเตอร์ที่คุณระบุไว้ในonProvideShadowMetrics() เมธอดนี้จะวาดเงาการลากบน Canvas ที่ระบุ

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

Listener เหตุการณ์การลากและเมธอด Callback

A View จะได้รับเหตุการณ์การลากด้วย Listener เหตุการณ์การลากที่ใช้ View.OnDragListener หรือด้วยเมธอด Callback onDragEvent() ของมุมมอง เมื่อ ระบบเรียกใช้เมธอดหรือ Listener ระบบจะระบุอาร์กิวเมนต์ DragEvent

ในกรณีส่วนใหญ่ การใช้ Listener จะดีกว่าการใช้เมธอด Callback เมื่อออกแบบ UI คุณมักจะไม่สร้างคลาสย่อยของคลาส View แต่การใช้เมธอด Callback จะบังคับให้คุณสร้างคลาสย่อยเพื่อลบล้างเมธอด ในทางกลับกัน คุณสามารถใช้คลาส Listener เดียวและใช้คลาสนี้กับออบเจ็กต์ View ที่แตกต่างกันหลายรายการได้ นอกจากนี้ คุณยังใช้คลาส Listener เป็นคลาสอินไลน์ที่ไม่ระบุชื่อหรือนิพจน์ Lambda ได้ด้วย หากต้องการตั้งค่า Listener สำหรับออบเจ็กต์ View ให้เรียกใช้ setOnDragListener()

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

  • แสดงผล "จริง" เพื่อตอบสนองต่อการเรียกใช้ startDragAndDrop()
  • เรียกใช้ performReceiveContent() หากมีการวางข้อมูลลากและวางในมุมมอง ระบบจะส่งข้อมูลไปยัง เมธอดเป็นออบเจ็กต์ ContentInfo เมธอดจะเรียกใช้ OnReceiveContentListener

  • แสดงผล "จริง" หากมีการวางข้อมูลลากและวางในมุมมองและ OnReceiveContentListener ใช้เนื้อหาบางส่วน

กำหนด OnReceiveContentListener เพื่อจัดการข้อมูลสำหรับ แอปของคุณโดยเฉพาะ หากต้องการความเข้ากันได้แบบย้อนกลับลงไปจนถึงระดับ API 24 ให้ใช้เวอร์ชัน Jetpack ของ OnReceiveContentListener

คุณสามารถมี Listener เหตุการณ์การลากและเมธอด Callback สำหรับออบเจ็กต์ View ได้ ในกรณีนี้ระบบจะเรียกใช้ Listener ก่อน ระบบจะไม่เรียกใช้เมธอด Callback เว้นแต่ Listener จะแสดงผล false

การรวมกันของเมธอด onDragEvent() และ View.OnDragListener จะคล้ายกับการรวมกันของ onTouchEvent() และ View.OnTouchListener ที่ใช้กับเหตุการณ์การสัมผัส