توضّح الأقسام التالية بعض المفاهيم الرئيسية لعملية السحب والإفلات.
عملية السحب والإفلات
هناك أربع خطوات أو حالات في عملية السحب والإفلات: "البدء"، "المتابعة"، و"الإفلات"، و"الانتهاء".
- قيد التشغيل
استجابةً لإيماءة سحب المستخدم، يُطلِق تطبيقك
startDragAndDrop()لإعلام النظام ببدء عملية السحب والإفلات. توفّر وسيطات المحاولة ما يلي:- البيانات التي سيتم سحبها
- دالة استدعاء لرسم ظل السحب
- بيانات التعريف التي تصف البيانات التي تم سحبها
- يستجيب النظام من خلال معاودة الاتصال بتطبيقك للحصول على تأثير التمرير الظل. بعد ذلك، يعرض النظام ظل السحب على الجهاز.
- بعد ذلك، يرسل النظام حدث سحب بنوع الإجراء
ACTION_DRAG_STARTEDإلى مستمع حدث السحب لجميع عناصرViewفي التنسيق الحالي. لمواصلة تلقّي أحداث السحب، بما في ذلك حدث التمرير الناجح، يجب أن تعرض أداة معالجة أحداث السحب القيمةtrue. يؤدي ذلك إلى تسجيل المستمع في النظام. يستمر فقط المستمعون المسجّلون فيتلقّي أحداث السحب. في هذه المرحلة، يمكن للمستمعِين أيضًا تغيير مظهر عنصرViewالمستهدَف للإسقاط للإشارة إلى أنّ العرض يمكنه قبول حدث إسقاط. - إذا أرجع مستمع أحداث السحب القيمة
false، لن يتلقّى أحداث سحب للعملية الحالية إلى أن يرسل النظام حدث سحب بنوع الإجراءACTION_DRAG_ENDED. من خلال عرض القيمةfalse، يُعلم المستمع النظام بأنّه ليس مهتمًا بعملية السحب والإفلات ولا يريد قبول البيانات التي تم سحبها.
- جارٍ المتابعة
- يواصل المستخدم السحب. عندما يتقاطع ظل السحب مع
المربّع الحدودي لأحد أهداف إسقاط العناصر، يُرسِل النظام حدث سحب واحدًا أو أكثر إلى
أداة معالجة أحداث السحب في الهدف. قد يغيّر المستمع مظهر
هدف إسقاط العنصر
Viewاستجابةً للحدث. على سبيل المثال، إذا كان الحدث يشير إلى أنّ ظل السحب يدخل في المربّع الحدودي لهدف التمرير لأسفل، وهو نوع الإجراءACTION_DRAG_ENTERED، يمكن للمستمع التفاعل من خلال تمييزView. - تم الإسقاط
- يُفلِت المستخدم ظل السحب داخل مربّع الحدود لهدف
الإفلات. يُرسِل النظام إلى أداة معالجة أحداث إسقاط العنصر حدث سحب بنوع
ACTION_DROP. يحتوي عنصر حدث السحب على البيانات التي يتم تمريرها إلى النظام في طلبstartDragAndDrop()الذي يبدأ العملية. من المفترض أن يُرجع المستمع قيمة منطقيةtrueإلى النظام إذا تمت معالجة البيانات التي تم إسقاطها بنجاح. : لا تحدث هذه الخطوة إلا إذا أسقط المستخدم ظل السحب داخل المربّع الحدودي لعنصرViewتم تسجيل مستمعه لتلقّي أحداث السحب (هدف إسقاط). إذا أفلَت المستخدم ظلّ السحب في أي حالة أخرى، لن يتمACTION_DROPإرسال حدث السحب. - انتهى
بعد أن يُطلِق المستخدم ظلّ السحب، وبعد أن يُرسِل النظام
حدث سحب بنوع الإجراء
ACTION_DROP، إذا لزم الأمر، يُرسِل النظام حدث سحب بنوع الإجراءACTION_DRAG_ENDEDللإشارة إلى أنّه انتهت عملية السحب والإفلات. ويتم ذلك بغض النظر عن المكان الذي يليه يُفلت المستخدم ظلّ السحب. يتم إرسال الحدث إلى كل مستمع تم تسجيله لتلقّي أحداث السحب، حتى إذا كان المستمع يتلقّى أيضًا حدثACTION_DROP.
يتم وصف كل خطوة من هذه الخطوات بمزيد من التفصيل في القسم المُعنوَن عملية السحب والإفلات.
سحب الأحداث
يُرسِل النظام حدث سحب في شكل عنصر DragEvent يحتوي على نوع إجراء يصف ما يحدث في عملية السحب والإفلات. استنادًا إلى نوع الإجراء، يمكن أن يحتوي العنصر أيضًا على بيانات أخرى.
تتلقّى أدوات معالجة أحداث السحب العنصر DragEvent. للحصول على نوع الإجراء،
يتصل المستمعون بالرقم
DragEvent.getAction().
هناك ست قيم محتملة تحدّدها الثوابت في فئة DragEvent،
والموضّحة في الجدول 1:
الجدول 1: أنواع إجراءات DragEvent
| نوع الإجراء | المعنى |
|---|---|
ACTION_DRAG_STARTED |
يُطلِق التطبيق startDragAndDrop() ويحصل على
ظلّ السحب. إذا أراد المستمع مواصلة تلقّي أحداث السحب
لهذه العملية، يجب أن يعرض القيمة المنطقية true
للنظام.
|
ACTION_DRAG_ENTERED |
يدخل ظل السحب في مربّع الحدود الخاص بملف
View الخاص بأداة معالجة أحداث السحب. هذا هو نوع الإجراء الأول للحدث الذي يتلقّاه المستمع
عندما يدخل ظل السحب إلى المربّع الحدودي.
|
ACTION_DRAG_LOCATION |
بعد حدث
ACTION_DRAG_ENTERED، يظلّ ظل السحب
ضمن مربّع الحدود الخاص بملف
View الخاص بأداة معالجة أحداث السحب.
|
ACTION_DRAG_EXITED |
بعد حدث ACTION_DRAG_ENTERED وحدث واحد على الأقل
ACTION_DRAG_LOCATION، يتحرك ظل السحب
خارج مربّع الحدود الخاص بView أداة معالجة أحداث السحب.
|
ACTION_DROP |
يتم تحرير ظل السحب فوق
View الخاصة بأداة معالجة أحداث السحب. لا يتم إرسال نوع الإجراء هذا إلى أداة معالجة حدث View
عنصر إلا إذا كانت أداة المعالجة تُرجع قيمة منطقية
true استجابةً لحدث السحب
ACTION_DRAG_STARTED. لا يتم
إرسال نوع الإجراء هذا إذا حرر المستخدم ظل السحب فوق View
لم يتم تسجيل مستمع له أو إذا حرر المستخدم ظل السحب
فوق أي عنصر ليس جزءًا من التنسيق الحالي.
يعرض المستمع القيمة المنطقية |
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. يتم تمرير أداة الإنشاء إلى النظام عند بدء عملية سحب وإفلات
باستخدام startDragAndDrop(). كجزء من استجابته لطلب
startDragAndDrop()، يستدعي النظام طرق الاستدعاء التي تحدّدها في
View.DragShadowBuilder للحصول على ظلّ السحب.
تحتوي فئة View.DragShadowBuilder على عنصرَي إنشاء:
View.DragShadowBuilder(View)يقبل هذا المُنشئ أيًا من ملفاتك الشخصية
Viewفي التطبيق. تخزِّن الدالة الإنشائية كائنViewفي كائنView.DragShadowBuilder، حتى تتمكّن وظائف الاستدعاء مجددًا من الوصول إليه لإنشاء ظل السحب. ولا يجب أن تكون طريقة العرض هيViewالتي يختارها المستخدم لبدء عملية السحب.في حال استخدام هذا المُنشئ، ليس عليك توسيع
View.DragShadowBuilderأو إلغاء طرقه. تلقائيًا، يظهر لك تأثير م拖شد بالشكل نفسه الذي يظهر بهViewالذي يتم تمريره كوسيطة، ويظهر أثره في وسط الشاشة أسفل المكان الذي يلمس فيه المستخدم الشاشة.View.DragShadowBuilder()في حال استخدام هذه الدالة الإنشائية، لن يتوفّر كائن
Viewفي كائنView.DragShadowBuilder. تم ضبط الحقل علىnull. يجب تمديدView.DragShadowBuilderوإلغاء طرقه، وإلا ستحصل على ظلّ سحب غير مرئي. لا يُرسِل النظام أي خطأ.
تحتوي فئة View.DragShadowBuilder على طريقتَين تؤديان معًا إلى إنشاء تأثير التمرير
الظل:
onProvideShadowMetrics()يستدعي النظام هذه الطريقة فورًا بعد الاتصال بـ
startDragAndDrop(). استخدِم الطريقة لإرسال السمات ونقطة لمس ظل السحب إلى النظام. تحتوي الطريقة على مَعلمتَين:
outShadowSize: عنصرPointيُحدَّد عرض ظل السحب فيx، وارتفاعه فيy.
outShadowTouchPoint: عنصرPointنقطة اللمس هي الموقع داخل ظل السحب الذي يجب أن يكون تحت إصبع المستخدم أثناء السحب. يُدرج موضع X فيxوموضع Y فيy.onDrawShadow()بعد استدعاء
onProvideShadowMetrics()مباشرةً، يستدعي النظامonDrawShadow()لإنشاء ظل السحب. تحتوي الطريقة على ملف شخصي واحد، وهو عنصرCanvasينشئه النظام من المَعلمات التي تقدّمها فيonProvideShadowMetrics(). ترسم الطريقة ظل السحب علىCanvasالمقدَّم.
لتحسين الأداء، يجب إبقاء حجم ظل السحب صغيرًا. بالنسبة إلى عنصر واحد، يمكنك استخدام رمز. عند اختيار عدة عناصر، قد تحتاج إلى استخدام رمز في حزمة بدلاً من صور كاملة منتشرة على الشاشة.
سحب أدوات معالجة الأحداث وطرق الاستدعاء
يتلقّى View أحداث السحب باستخدام مستمع أحداث السحب الذي ينفِّذ
View.OnDragListener أو باستخدام طريقة الاستدعاء onDragEvent() للعرض. عندما
يُطلِب النظام الطريقة أو المستمع، يقدّم DragEvent وسيطة.
في معظم الحالات، يُفضَّل استخدام مستمع بدلاً من استخدام طريقة طلب الاستدعاء. عند
تصميم واجهات المستخدم، لا تنشئ عادةً فئات فرعية لفئات View، ولكن استخدام أسلوب
callback يجبرك على إنشاء فئات فرعية لتحل محل الأسلوب. في مقارنة، يمكنك تنفيذ فئة مستمع واحدة ثم استخدامها مع عدة
كائنات View مختلفة. يمكنك أيضًا تنفيذها كصفّ مضمّن مجهول
أو تعبير لامبادا. لضبط مستمع لعنصر View، اتصل بـ
setOnDragListener().
بدلاً من ذلك، يمكنك تغيير التنفيذ التلقائي onDragEvent()
بدون إلغاء الطريقة. اضبط
OnReceiveContentListener
على عرض. لمزيد من التفاصيل، اطّلِع على
setOnReceiveContentListener().
بعد ذلك، تُجري طريقة onDragEvent() ما يلي تلقائيًا:
- تعرِض القيمة "صحيح" استجابةً للطلب الذي تم توجيهه إلى
startDragAndDrop(). المكالمات
performReceiveContent()في حال إسقاط بيانات السحب والإفلات على طريقة العرض يتم تمرير البيانات إلى المحاولة ككائنContentInfo. تستدعي المحاولةOnReceiveContentListener.تعرِض هذه السمة القيمة "صحيح" إذا تم إسقاط بيانات السحب والإفلات على طريقة العرض واستهلاك
OnReceiveContentListenerلأيّ من المحتوى.
حدِّد OnReceiveContentListener لمعالجة البيانات خصيصًا ل
تطبيقك. للتوافق مع الإصدارات القديمة حتى المستوى 24 من واجهة برمجة التطبيقات، استخدِم إصدار Jetpack من
OnReceiveContentListener.
يمكنك استخدام أداة معالجة أحداث السحب وطريقة استدعاء لعنصر View،
وفي هذه الحالة يستدعي النظام أداة المعالجة أولاً. لا يستدعي النظام أسلوب
callback ما لم يُرجع المستمع القيمة false.
إنّ الجمع بين الطريقة onDragEvent() وView.OnDragListener هو
مشابه للجمع بين
onTouchEvent()
وView.OnTouchListener
المستخدَمَين مع أحداث اللمس.