المفاهيم الرئيسية

تشرح الأقسام التالية بعض المفاهيم الأساسية لعملية السحب والإفلات.

عملية السحب والإفلات

هناك أربع خطوات أو حالات في عملية السحب والإفلات: البدء والاستمرار والإفلات والإنهاء.

تم بدء التنفيذ.

استجابةً لإيماءة السحب التي أجراها المستخدم، يطلب تطبيقك الرمز 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 الذي لم يتم تسجيل أداة الاستماع إليه أو إذا أطلق المستخدم ظل السحب على أي عنصر ليس جزءًا من التنسيق الحالي.

يعرض المستمع true القيمة المنطقية إذا عالج عملية الانخفاض بنجاح. وبخلاف ذلك، يجب أن يعرض السمة false.

ACTION_DRAG_ENDED يُنهي النظام عملية السحب والإفلات. ليس بالضرورة أن يكون نوع الإجراء هذا مسبوقًا بحدث ACTION_DROP. إذا أرسل النظام ACTION_DROP، لن يعني تلقّي نوع الإجراء ACTION_DRAG_ENDED أنّه تم الانخفاض بنجاح. على المستمع طلب getResult()، كما هو موضّح في الجدول 2، للحصول على القيمة التي يتم عرضها استجابةً للسمة ACTION_DROP. إذا لم يتم إرسال حدث ACTION_DROP، ستعرض السمة getResult() القيمة false.

يحتوي الكائن DragEvent أيضًا على البيانات والبيانات الوصفية التي يوفّرها تطبيقك للنظام في طلب startDragAndDrop(). بعض البيانات صالحة فقط لأنواع إجراءات معينة كما هو موضح في الجدول 2. لمزيد من المعلومات حول الأحداث والبيانات المرتبطة بها، يمكنك الاطّلاع على قسم عملية السحب والإفلات.

الجدول 2. بيانات DragEvent الصالحة حسب نوع الإجراء

قيمة
getAction()
قيمة
getClipDescription()
قيمة
getLocalState()
قيمة
getX()
قيمة
getY()
قيمة
getClipData()
قيمة
getResult()
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 الفرعية، ولكن استخدام طريقة معاودة الاتصال يفرض عليك إنشاء فئات فرعية لإلغاء الطريقة. وبالمقارنة، يمكنك تطبيق فئة مستمع واحدة ثم استخدامها مع عدة كائنات View مختلفة. يمكنك أيضًا تنفيذه كتعبير مضمّن مجهول الهوية أو تعبير lambda. لضبط أداة المستمع لكائن View، يمكنك طلب setOnDragListener().

كخيار بديل، يمكنك تغيير طريقة التنفيذ التلقائية للسمة onDragEvent() بدون إلغاء الطريقة. اضبط OnReceiveContentListener على عرض. لمزيد من التفاصيل، راجِع setOnReceiveContentListener(). بعد ذلك، تنفِّذ الطريقة onDragEvent() ما يلي تلقائيًا:

  • يتم عرض القيمة "صحيح" استجابةً للمكالمة الواردة إلى startDragAndDrop().
  • استدعاء performReceiveContent() إذا تم إسقاط بيانات السحب والإفلات في العرض. يتم تمرير البيانات إلى الطريقة ككائن ContentInfo. تستدعي الطريقة OnReceiveContentListener.

  • يتم عرض القيمة "صحيح" إذا تم إسقاط بيانات السحب والإفلات في العرض وكان OnReceiveContentListener يستهلك أيًا من المحتوى.

حدِّد OnReceiveContentListener لمعالجة بيانات تطبيقك تحديدًا. للتوافق مع الأنظمة القديمة وصولاً إلى المستوى 24 من واجهة برمجة التطبيقات، استخدِم إصدار Jetpack من OnReceiveContentListener.

يمكنك استخدام أداة معالجة حدث السحب وطريقة لمعاودة الاتصال لكائن View، وفي هذه الحالة يطلب النظام المستمع أولاً. ولا يستدعي النظام طريقة معاودة الاتصال ما لم يعرض المستمع false.

يُشابه الجمع بين طريقة onDragEvent() وView.OnDragListener للجمع بين onTouchEvent() وView.OnTouchListener المستخدَمين مع أحداث اللمس.