ส่วนต่อไปนี้จะอธิบายแนวคิดสําคัญ 2-3 ข้อสําหรับกระบวนการลากและวาง
กระบวนการลากและวาง
กระบวนการลากและวางมี 4 ขั้นตอนหรือสถานะ ได้แก่ เริ่ม ดำเนินการต่อ วาง และสิ้นสุด
- เริ่มต้นแล้ว
ในการตอบสนองต่อท่าทางสัมผัสการลากของผู้ใช้ แอปพลิเคชันจะเรียกใช้
startDragAndDrop()เพื่อบอกให้ระบบเริ่มการลากและวาง อาร์กิวเมนต์ของเมธอดจะระบุข้อมูลต่อไปนี้- ข้อมูลที่จะลาก
- โค้ดเรียกกลับสำหรับการวาดเงาการลาก
- ข้อมูลเมตาที่อธิบายข้อมูลที่ลาก
- ระบบจะตอบสนองด้วยการเรียกกลับไปยังแอปพลิเคชันของคุณเพื่อรับการลากเงา จากนั้นระบบจะแสดงเงาการลากบนอุปกรณ์
- จากนั้นระบบจะส่งเหตุการณ์การลากที่มีประเภทการดําเนินการ
ACTION_DRAG_STARTEDไปยัง ฟังก์ชันการฟังเหตุการณ์การลาก ของออบเจ็กต์Viewทั้งหมดในเลย์เอาต์ปัจจุบัน หากต้องการรับเหตุการณ์การลากต่อไป ซึ่งรวมถึงเหตุการณ์การวางที่เป็นไปได้ Listener เหตุการณ์การลากต้องแสดงผลtrueซึ่งจะลงทะเบียน Listener กับระบบ เฉพาะผู้ฟังที่ลงทะเบียนไว้เท่านั้นที่จะยังคงได้รับเหตุการณ์การลาก เมื่อถึงจุดนี้ โปรแกรมฟังยังเปลี่ยนลักษณะที่ปรากฏของออบเจ็กต์เป้าหมายการวางViewเพื่อแสดงให้เห็นว่ามุมมองยอมรับเหตุการณ์การวางได้ด้วย - หากตัวรับฟังเหตุการณ์การลากแสดงผลเป็น
falseแสดงว่าไม่ได้รับการลากเหตุการณ์สําหรับการดำเนินการปัจจุบันจนกว่าระบบจะส่งเหตุการณ์การลากที่มีประเภทการดําเนินการACTION_DRAG_ENDEDการคืนค่าfalseเป็นการบอกให้ระบบทราบว่าไม่สนใจการดำเนินการลากและวาง และไม่ต้องการยอมรับข้อมูลที่ลากมา
- ต่อไป
- ผู้ใช้ลากต่อ เมื่อเงาการลากตัดกับกล่องขอบเขตของเป้าหมายการวาง ระบบจะส่งเหตุการณ์การลากอย่างน้อย 1 รายการไปยัง Listener เหตุการณ์การลากของเป้าหมาย โปรแกรมฟังอาจเปลี่ยนลักษณะที่ปรากฏของเป้าหมายการลากวาง
Viewเพื่อตอบสนองต่อเหตุการณ์ ตัวอย่างเช่น หากเหตุการณ์บ่งชี้ว่าเงาการลากเข้าสู่กล่องขอบเขตของเป้าหมายการปล่อยประเภทการดำเนินการACTION_DRAG_ENTEREDโปรแกรมฟังเหตุการณ์จะตอบสนองด้วยการไฮไลต์View - ยกเลิก
- ผู้ใช้ปล่อยเงาการลากภายในขอบเขตของเป้าหมายการวาง ระบบจะส่งเหตุการณ์การลากที่มีประเภทการดำเนินการ
ACTION_DROPไปยัง Listener ของเป้าหมายการวาง ออบเจ็กต์เหตุการณ์การลากมีข้อมูลที่ส่งไปยังระบบในการเรียกใช้startDragAndDrop()ที่เริ่มการดำเนินการ คาดว่า Listener จะแสดงผลบูลีนtrueไปยังระบบหาก Listener ประมวลผลข้อมูลที่ทิ้งได้สําเร็จ : ขั้นตอนนี้จะเริ่มต้นขึ้นก็ต่อเมื่อผู้ใช้วางเงาการลากภายในกล่องขอบเขตของViewที่ลงทะเบียน Listener เพื่อรับเหตุการณ์การลาก (เป้าหมายการวาง) หากผู้ใช้ปล่อยเงาการลากในสถานการณ์อื่นๆ ระบบจะไม่ACTION_DROPส่งเหตุการณ์การลาก - สิ้นสุดแล้ว
หลังจากผู้ใช้ปล่อยเงาการลาก และหลังจากระบบส่ง
เหตุการณ์การลากที่มีประเภทการดำเนินการ
ACTION_DROPหากจำเป็น ระบบจะส่งเหตุการณ์การลากที่มีประเภทการดำเนินการACTION_DRAG_ENDEDเพื่อระบุว่าการดำเนินการลากและวางสิ้นสุดแล้ว การดำเนินการนี้จะดำเนินการไม่ว่าผู้ใช้จะปล่อยเงาการลากไว้ที่ใดก็ตาม ระบบจะส่งเหตุการณ์ไปยังผู้ฟังทุกคนที่ลงทะเบียนเพื่อรับเหตุการณ์การลาก แม้ว่าผู้ฟังจะได้รับเหตุการณ์ACTION_DROPด้วยก็ตาม
อ่านคำอธิบายขั้นตอนเหล่านี้แต่ละขั้นตอนอย่างละเอียดได้ที่ส่วนที่เรียกว่าการดำเนินการแบบลากและวาง
เหตุการณ์การลาก
ระบบจะส่งเหตุการณ์การลากในรูปแบบออบเจ็กต์ DragEvent ซึ่งมีประเภทการดำเนินการที่อธิบายสิ่งที่เกิดขึ้นในกระบวนการลากและวาง ออบเจ็กต์อาจมีข้อมูลอื่นๆ ด้วย ทั้งนี้ขึ้นอยู่กับประเภทการดำเนินการ
Listener เหตุการณ์การลากจะได้รับออบเจ็กต์ DragEvent หากต้องการดูประเภทการดำเนินการ ผู้ฟังจะโทรไปที่ DragEvent.getAction()
ค่าที่เป็นไปได้มี 6 ค่าซึ่งกำหนดโดยค่าคงที่ในคลาส DragEvent ซึ่งอธิบายไว้ในตารางที่ 1
ตารางที่ 1 ประเภทการดำเนินการของ DragEvent
| ประเภทการดําเนินการ | ความหมาย |
|---|---|
ACTION_DRAG_STARTED |
แอปพลิเคชันเรียก startDragAndDrop() และรับเงาการลาก หากตัวฟังต้องการรับเหตุการณ์การลากสําหรับการดำเนินการนี้ต่อไป จะต้องแสดงผลบูลีน true ไปยังระบบ
|
ACTION_DRAG_ENTERED |
เงาการลากเข้าสู่ขอบเขตของ View ของ Listener เหตุการณ์การลาก นี่คือประเภทการดำเนินการของเหตุการณ์แรกๆ ที่ Listener ได้รับเมื่อเงาการลากเข้าสู่ขอบเขต
|
ACTION_DRAG_LOCATION |
หลังจากเหตุการณ์ ACTION_DRAG_ENTERED เกิด เงาบดยังคงอยู่ภายในกล่องขอบเขตของ View ของ Listener เหตุการณ์การลาก
|
ACTION_DRAG_EXITED |
หลังจากเหตุการณ์ ACTION_DRAG_ENTERED และเหตุการณ์ ACTION_DRAG_LOCATION อย่างน้อย 1 รายการ เงาการลากจะย้ายออกนอกขอบเขตของ View ของ Listener เหตุการณ์การลาก
|
ACTION_DROP |
เงาการลากจะปล่อยเหนือ View ของ Listener เหตุการณ์การลาก ระบบจะส่งประเภทการดําเนินการนี้ไปยัง Listener ของView
ออบเจ็กต์ก็ต่อเมื่อ Listener แสดงผลบูลีน true เพื่อตอบสนองACTION_DRAG_STARTEDเหตุการณ์การลาก ระบบจะไม่ส่งการดําเนินการประเภทนี้หากผู้ใช้ปล่อยเงาการลากเหนือ View ที่ยังไม่ได้ลงทะเบียน Listener หรือหากผู้ใช้ปล่อยเงาการลากเหนือสิ่งที่ไม่ได้เป็นส่วนหนึ่งของเลย์เอาต์ปัจจุบัน
โปรแกรมฟังจะแสดงผลบูลีน |
ACTION_DRAG_ENDED |
ระบบกำลังสิ้นสุดการดำเนินการลากและวาง ประเภทการดําเนินการนี้ไม่จำเป็นต้องมีเหตุการณ์ ACTION_DROP มาก่อน หากระบบส่ง ACTION_DROP การได้รับประเภทการดําเนินการ ACTION_DRAG_ENDED ไม่ได้หมายความว่าการปล่อยสําเร็จ ผู้ฟังต้องเรียกใช้ getResult() ตามที่แสดงในตารางที่ 2 เพื่อรับค่าที่แสดงผลเพื่อตอบสนองต่อ ACTION_DROP หากไม่มีการส่งเหตุการณ์ ACTION_DROP getResult() จะแสดงผลเป็น false
|
ออบเจ็กต์ DragEvent ยังมีข้อมูลและข้อมูลเมตาที่แอปพลิเคชันของคุณระบุให้กับระบบในการเรียกใช้ startDragAndDrop() ด้วย ข้อมูลบางอย่างใช้ได้กับการดำเนินการบางประเภทเท่านั้นตามที่สรุปไว้ในตาราง 2 ดูข้อมูลเพิ่มเติมเกี่ยวกับเหตุการณ์และข้อมูลที่เชื่อมโยงได้ที่ส่วนการดำเนินการแบบลากและวาง
ตารางที่ 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() ในการตอบสนองต่อ startDragAndDrop() ระบบจะเรียกใช้เมธอดการเรียกกลับที่คุณกำหนดไว้ใน View.DragShadowBuilder เพื่อรับเงาการลาก
คลาส View.DragShadowBuilder มีคอนสตรัคเตอร์ 2 รายการ ดังนี้
View.DragShadowBuilder(View)ตัวสร้างคอนสตรัคเตอร์นี้ยอมรับออบเจ็กต์
Viewของแอปพลิเคชัน ตัวสร้างจะจัดเก็บออบเจ็กต์Viewไว้ในออบเจ็กต์View.DragShadowBuilderเพื่อให้การเรียกกลับเข้าถึงเพื่อสร้างเงาการลากได้ มุมมองไม่จำเป็นต้องเป็น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()ทันทีหลังจากการเรียก
onProvideShadowMetrics()ระบบจะเรียกonDrawShadow()เพื่อสร้างเงาการลาก เมธอดนี้มีอาร์กิวเมนต์เดียว ซึ่งเป็นออบเจ็กต์Canvasที่ระบบสร้างขึ้นจากพารามิเตอร์ที่คุณระบุในonProvideShadowMetrics()เมธอดจะวาดเงาการลากในCanvasที่ระบุ
ปรับขนาดเงาการลากให้เล็กเพื่อเพิ่มประสิทธิภาพ สำหรับรายการเดียว คุณอาจต้องใช้ไอคอน สำหรับการเลือกหลายรายการ คุณอาจต้องใช้ไอคอนในกองแทนรูปภาพขนาดเต็มกระจายอยู่ทั่วหน้าจอ
ลาก Listener เหตุการณ์และเมธอดการเรียกกลับ
View จะได้รับเหตุการณ์การลากด้วย Listener เหตุการณ์การลากที่ใช้ View.OnDragListener หรือด้วยเมธอด Callback onDragEvent() ของมุมมอง เมื่อระบบเรียกใช้เมธอดหรือ Listener ระบบจะระบุอาร์กิวเมนต์ DragEvent
ในกรณีส่วนใหญ่ การใช้ Listener นั้นดีกว่าการใช้เมธอดการเรียกกลับ เมื่อออกแบบ UI คุณมักจะไม่ได้สร้างคลาสย่อยของ View แต่การใช้เมธอด callback จะทำให้คุณต้องสร้างคลาสย่อยเพื่อลบล้างเมธอด ในทางกลับกัน คุณสามารถใช้คลาส Listener 1 คลาสกับออบเจ็กต์ View หลายรายการที่แตกต่างกันได้ นอกจากนี้ คุณยังใช้ Lambda นี้เป็นคลาสอินไลน์นิรนามหรือนิพจน์ Lambda ได้ด้วย หากต้องการตั้งค่าตัวรับฟังสําหรับออบเจ็กต์ View ให้เรียกใช้
setOnDragListener()
หรือจะเปลี่ยนการใช้งานเริ่มต้นของ onDragEvent()
โดยไม่ต้องลบล้างเมธอดก็ได้ ตั้งค่า
OnReceiveContentListener
ในมุมมอง ดูรายละเอียดเพิ่มเติมได้ที่
setOnReceiveContentListener()
จากนั้นเมธอด onDragEvent() จะทําสิ่งต่อไปนี้โดยค่าเริ่มต้น
- แสดงผลเป็น "จริง" เพื่อตอบสนองการเรียกใช้
startDragAndDrop() การโทร
performReceiveContent()หากมีการวางข้อมูลการลากและวางในมุมมอง ระบบจะส่งข้อมูลไปยังเมธอดเป็นออบเจ็กต์ContentInfoวิธีการเรียกใช้OnReceiveContentListenerแสดงผลเป็น "จริง" หากมีการวางข้อมูลการลากและวางในมุมมอง และ
OnReceiveContentListenerใช้เนื้อหาใดก็ตาม
กำหนด OnReceiveContentListener เพื่อจัดการข้อมูลสำหรับแอปของคุณโดยเฉพาะ หากต้องการความเข้ากันได้แบบย้อนหลังจนถึง API ระดับ 24 ให้ใช้ OnReceiveContentListener เวอร์ชัน Jetpack
คุณมี Listener เหตุการณ์การลากและเมธอด Callback สําหรับออบเจ็กต์ View ได้ ซึ่งในกรณีนี้ระบบจะเรียก Listener ก่อน ระบบจะไม่เรียกใช้เมธอด callback เว้นแต่ตัวฟังจะแสดงผล false
การรวมวิธีการ onDragEvent() กับ View.OnDragListener นั้นคล้ายกับการรวม onTouchEvent() กับ View.OnTouchListener ที่ใช้กับเหตุการณ์การสัมผัส