ส่วนต่อไปนี้จะอธิบายแนวคิดสําคัญ 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
และความสูงจะอยู่ในy
outShadowTouchPoint
: ออบเจ็กต์Point
จุดสัมผัสคือตําแหน่งภายในเงาการลากซึ่งต้องอยู่ใต้นิ้วของผู้ใช้ขณะลาก ตำแหน่ง X ขององค์ประกอบจะอยู่ในx
และตำแหน่ง Y ขององค์ประกอบจะอยู่ในy
onDrawShadow()
ทันทีหลังจากการเรียก
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
ที่ใช้กับเหตุการณ์การสัมผัส