ส่วนต่อไปนี้จะอธิบายแนวคิดหลักบางประการสำหรับกระบวนการลากและวาง
กระบวนการลากและวาง
กระบวนการลากและวางมี 4 ขั้นตอนหรือสถานะ ได้แก่ เริ่มต้น กำลังดำเนินการต่อ วาง และสิ้นสุด
- เริ่มต้นแล้ว
แอปพลิเคชันจะเรียกใช้
startDragAndDrop()เพื่อบอกให้ระบบเริ่มการดำเนินการลากและวางเพื่อตอบสนองต่อท่าทางสัมผัสลากของผู้ใช้ อาร์กิวเมนต์ของเมธอดจะระบุข้อมูลต่อไปนี้- ข้อมูลที่จะลาก
- Callback สำหรับการวาดเงาการลาก
- ข้อมูลเมตาที่อธิบายข้อมูลที่ลาก
- ระบบจะตอบกลับด้วยการเรียกกลับไปยังแอปพลิเคชันของคุณเพื่อรับเงาการลาก จากนั้นระบบจะแสดงเงาการลากบนอุปกรณ์
- จากนั้นระบบจะส่งเหตุการณ์การลากที่มีประเภทการดำเนินการ
ACTION_DRAG_STARTEDไปยัง Listener เหตุการณ์การลากของออบเจ็กต์Viewทั้งหมดในเลย์เอาต์ปัจจุบัน Listener เหตุการณ์การลากต้องแสดงผลtrueเพื่อรับเหตุการณ์การลากต่อไป ซึ่งรวมถึงเหตุการณ์การวางที่อาจเกิดขึ้น การดำเนินการนี้จะลงทะเบียน Listener กับระบบ เฉพาะ Listener ที่ลงทะเบียนแล้วเท่านั้นที่จะได้รับเหตุการณ์การลากต่อไป นอกจากนี้ Listener ยังสามารถเปลี่ยนลักษณะที่ปรากฏของออบเจ็กต์Viewเป้าหมายการวางเพื่อแสดงว่ามุมมองยอมรับเหตุการณ์การวางได้ - หาก Listener เหตุการณ์การลากแสดงผล
falseListener จะไม่ได้รับเหตุการณ์ การลากสำหรับการดำเนินการปัจจุบันจนกว่าระบบจะส่งเหตุการณ์การลาก ที่มีประเภทการดำเนินการACTION_DRAG_ENDEDการแสดงผลfalseจะบอกให้ระบบทราบว่า Listener ไม่สนใจการดำเนินการลากและวางและไม่ต้องการยอมรับข้อมูลที่ลาก
- กำลังดำเนินการต่อ
- ผู้ใช้ลากต่อไป เมื่อเงาการลากตัดกับกรอบล้อมรอบของเป้าหมายการวาง ระบบจะส่งเหตุการณ์การลากอย่างน้อย 1 เหตุการณ์ไปยัง Listener เหตุการณ์การลากของเป้าหมาย Listener อาจเปลี่ยนลักษณะที่ปรากฏของ
Viewเป้าหมายการวางเพื่อตอบสนองต่อเหตุการณ์ ตัวอย่างเช่น หากเหตุการณ์ ระบุว่าเงาการลากเข้าสู่กรอบล้อมรอบของเป้าหมายการวาง ประเภทการดำเนินการACTION_DRAG_ENTEREDListener สามารถตอบสนองด้วยการไฮไลต์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 จะแสดงผลบูลีน |
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และความสูงจะอยู่ในyoutShadowTouchPoint: ออบเจ็กต์Pointจุดสัมผัสคือตำแหน่งภายในเงาการลากที่ต้องอยู่ใต้ปลายนิ้วของผู้ใช้ระหว่างการลาก ตำแหน่ง X จะอยู่ในxและตำแหน่ง Y จะอยู่ในyonDrawShadow()ระบบจะเรียกใช้
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
ที่ใช้กับเหตุการณ์การสัมผัส