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

تجربة طريقة Compose
‫Jetpack Compose هي مجموعة أدوات واجهة المستخدم المقترَحة لنظام Android. تعرَّفوا على كيفية استخدام ميزة السحب والإفلات في Compose.

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

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

تتضمّن عملية السحب والإفلات أربع خطوات أو حالات: "تم البدء" و"جارٍ المتابعة" و"تم الإسقاط" و"أحداث منتهية".

تم البدء

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

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

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

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

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

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

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