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

تجربة ميزة "الكتابة"
‫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 عنصر إلا إذا كانت أداة المعالجة تُرجع قيمة منطقية 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، ولكن استخدام أسلوب 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 المستخدَمَين مع أحداث اللمس.