يتيح لك إطار عمل السحب والإفلات في Android إضافة إمكانيات السحب والإفلات
التفاعلية إلى تطبيقك. باستخدام السحب والإفلات، يمكن للمستخدمين نسخ أو نقل النص
والصور والكائنات وأي محتوى يمكن تمثيله بمعرّف موارد منتظم (URI)، من View
إلى آخر داخل تطبيق أو بين التطبيقات
في وضع النوافذ المتعددة.
|
|
يتضمن إطار العمل فئة حدث السحب، وأدوات معالجة السحب، وفئات وطرق مساعدة. على الرغم من أنّه تم تصميمه في المقام الأول لإتاحة نقل البيانات، يمكنك استخدام إطار العمل لإجراءات أخرى في واجهة المستخدم. على سبيل المثال، يمكنك إنشاء تطبيق يمزج بين الألوان عندما يسحب المستخدم أيقونة لون فوق أيقونة أخرى. ومع ذلك، تصف بقية المستند إطار عمل السحب والإفلات في سياق نقل البيانات.
نظرة عامة
تبدأ عملية السحب والإفلات عندما يُجري المستخدم إيماءة في واجهة المستخدم يتعرّف عليها تطبيقك كإشارة لبدء سحب البيانات. استجابةً لذلك، يبلغ التطبيق النظام ببدء عملية السحب والإفلات. يتصل النظام بالتطبيق مرة أخرى للحصول على تمثيل للبيانات التي يتم سحبها، ويسمى ظل السحب.
عندما يحرّك المستخدم ظل السحب فوق تنسيق التطبيق، يُرسِل النظام أحداث السحب إلى أدوات معالجة أحداث السحب وطرق معاودة الاتصال المرتبطة بكائنات View
في التنسيق. إذا حرر المستخدم ظل السحب فوق طريقة عرض
يمكنها قبول البيانات (هدف إفلات)، فسيرسل النظام البيانات إلى
الهدف. تنتهي عملية السحب والإفلات عندما يحرر المستخدم ظل السحب،
سواء كان ظل السحب فوق هدف الإفلات أم لا.
يمكنك إنشاء أداة معالجة حدث السحب من خلال تنفيذ
View.OnDragListener
. اضبط
أداة معالجة الحدث لهدف الانخفاض باستخدام الطريقة
setOnDragListener()
للكائن View
. تحتوي كل طريقة عرض في التنسيق أيضًا على
طريقة معاودة الاتصال
بـ onDragEvent()
.
يرسل تطبيقك إشعارًا إلى النظام ببدء عملية السحب والإفلات من خلال استدعاء الطريقة
startDragAndDrop()
التي تطلب من النظام إرسال أحداث السحب. توفر الطريقة أيضًا للنظام البيانات التي يسحبها
المستخدم وبيانات التعريف التي تصف البيانات. يمكنك استدعاء startDragAndDrop()
على أي View
بالتنسيق الحالي. يستخدم النظام العنصر View
فقط للوصول إلى الإعدادات العامة في التنسيق.
أثناء عملية السحب والإفلات، يرسل النظام أحداث السحب إلى أدوات معالجة أحداث السحب أو طرق رد الاتصال لكائنات View
في التنسيق. ويستخدم المستمعون أو طريقة معاودة الاتصال البيانات الوصفية لتحديد ما إذا كانوا يريدون قبول البيانات عند إسقاطها. إذا أفلت المستخدم البيانات في هدف
إفلات، وهو View
يقبل البيانات، يرسل النظام عنصر سحب
يحتوي على البيانات إلى طريقة استماع حدث السحب أو طريقة معاودة الاتصال في هدف الإفلات.
سحب أدوات معالجة الأحداث وطرق رد الاتصال
يتلقّى 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
المستخدَمين مع أحداث اللمس.
عملية السحب والإفلات
توجد أربع خطوات أو حالات في عملية السحب والإفلات: بدأت، ومستمرة، وأسقطت، وانتهت.
- تم بدء التنفيذ.
استجابة لإيماءة السحب التي أجراها المستخدم، يطلب تطبيقك الرمز
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:
نوع الإجراء | المعنى |
---|---|
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. للحصول على مزيد من المعلومات حول الأحداث والبيانات المرتبطة بها، يمكنك الاطلاع على قسم عملية السحب والإفلات.
القيمة 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
، وينتقل الموضع ص فيy
.onDrawShadow()
بعد اتصال
onProvideShadowMetrics()
مباشرةً، يستدعي النظامonDrawShadow()
لإنشاء تظليل السحب. تتضمّن الطريقة وسيطة واحدة، وهي كائنCanvas
ينشئها النظام من المَعلمات التي تقدّمها فيonProvideShadowMetrics()
. ترسم هذه الطريقة تظليل السحب علىCanvas
المقدَّم.
لتحسين الأداء، اجعل حجم تظليل السحب صغيرًا. لعنصر واحد، قد ترغب في استخدام أيقونة. للحصول على تحديد متعدد العناصر، قد ترغب في استخدام الأيقونات في مكدس بدلاً من الصور الكاملة المنتشرة على الشاشة.
عملية السحب والإفلات
يعرض هذا القسم خطوة بخطوة كيفية بدء عملية السحب، والاستجابة للأحداث أثناء السحب، والاستجابة لحدث الإفلات، وإنهاء عملية السحب والإفلات.
بدء السحب
يبدأ المستخدم عملية سحب بإيماءة سحب، وهي عادةً عبر النقر مع الاستمرار على عنصر View
. استجابةً لذلك، يجب أن ينفّذ تطبيقك الإجراءات التالية:
أنشئ كائن
ClipData
وكائنClipData.Item
للبيانات التي يتم نقلها. كجزء منClipData
، أدخِل البيانات الوصفية المخزّنة في عنصرClipDescription
ضمنClipData
. لإجراء عملية سحب وإفلات لا تمثّل حركة البيانات، قد تحتاج إلى استخدامnull
بدلاً من كائن فعلي.على سبيل المثال، يعرض مقتطف الرمز هذا كيفية الاستجابة لإيماءة النقر مع الاستمرار على
ImageView
من خلال إنشاء عنصرClipData
يحتوي على علامة (أو تصنيف)ImageView
:Kotlin
// Create a string for the ImageView label. val IMAGEVIEW_TAG = "icon bitmap" ... val imageView = ImageView(context).apply { // Set the bitmap for the ImageView from an icon bitmap defined elsewhere. setImageBitmap(iconBitmap) tag = IMAGEVIEW_TAG setOnLongClickListener { v -> // Create a new ClipData. This is done in two steps to provide // clarity. The convenience method ClipData.newPlainText() can // create a plain text ClipData in one step. // Create a new ClipData.Item from the ImageView object's tag. val item = ClipData.Item(v.tag as? CharSequence) // Create a new ClipData using the tag as a label, the plain text // MIME type, and the already-created item. This creates a new // ClipDescription object within the ClipData and sets its MIME type // to "text/plain". val dragData = ClipData( v.tag as? CharSequence, arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN), item) // Instantiate the drag shadow builder. val myShadow = MyDragShadowBuilder(view: this) // Start the drag. v.startDragAndDrop(dragData, // The data to be dragged. myShadow, // The drag shadow builder. null, // No need to use local data. 0 // Flags. Not currently used, set to 0. ) // Indicate that the long-click is handled. true } }
Java
// Create a string for the ImageView label. private static final String IMAGEVIEW_TAG = "icon bitmap"; ... // Create a new ImageView. ImageView imageView = new ImageView(context); // Set the bitmap for the ImageView from an icon bitmap defined elsewhere. imageView.setImageBitmap(iconBitmap); // Set the tag. imageView.setTag(IMAGEVIEW_TAG); // Set a long-click listener for the ImageView using an anonymous listener // object that implements the OnLongClickListener interface. imageView.setOnLongClickListener( v -> { // Create a new ClipData. This is done in two steps to provide clarity. The // convenience method ClipData.newPlainText() can create a plain text // ClipData in one step. // Create a new ClipData.Item from the ImageView object's tag. ClipData.Item item = new ClipData.Item((CharSequence) v.getTag()); // Create a new ClipData using the tag as a label, the plain text MIME type, // and the already-created item. This creates a new ClipDescription object // within the ClipData and sets its MIME type to "text/plain". ClipData dragData = new ClipData( (CharSequence) v.getTag(), new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN }, item); // Instantiate the drag shadow builder. View.DragShadowBuilder myShadow = new MyDragShadowBuilder(imageView); // Start the drag. v.startDragAndDrop(dragData, // The data to be dragged. myShadow, // The drag shadow builder. null, // No need to use local data. 0 // Flags. Not currently used, set to 0. ); // Indicate that the long-click is handled. return true; });
حدِّد
myDragShadowBuilder
من خلال إلغاء الطرق فيView.DragShadowBuilder
. يُنشئ مقتطف الرمز التالي ظلاً صغيرًا مستطيلًا للسحب باللون الرمادي لـTextView
:Kotlin
private class MyDragShadowBuilder(view: View) : View.DragShadowBuilder(view) { private val shadow = ColorDrawable(Color.LTGRAY) // Define a callback that sends the drag shadow dimensions and touch point // back to the system. override fun onProvideShadowMetrics(size: Point, touch: Point) { // Set the width of the shadow to half the width of the original // View. val width: Int = view.width / 2 // Set the height of the shadow to half the height of the original // View. val height: Int = view.height / 2 // The drag shadow is a ColorDrawable. Set its dimensions to // be the same as the Canvas that the system provides. As a result, // the drag shadow fills the Canvas. shadow.setBounds(0, 0, width, height) // Set the size parameter's width and height values. These get back // to the system through the size parameter. size.set(width, height) // Set the touch point's position to be in the middle of the drag // shadow. touch.set(width / 2, height / 2) } // Define a callback that draws the drag shadow in a Canvas that the system // constructs from the dimensions passed to onProvideShadowMetrics(). override fun onDrawShadow(canvas: Canvas) { // Draw the ColorDrawable on the Canvas passed in from the system. shadow.draw(canvas) } }
Java
private static class MyDragShadowBuilder extends View.DragShadowBuilder { // The drag shadow image, defined as a drawable object. private static Drawable shadow; // Constructor. public MyDragShadowBuilder(View view) { // Store the View parameter. super(view); // Create a draggable image that fills the Canvas provided by the // system. shadow = new ColorDrawable(Color.LTGRAY); } // Define a callback that sends the drag shadow dimensions and touch point // back to the system. @Override public void onProvideShadowMetrics (Point size, Point touch) { // Define local variables. int width, height; // Set the width of the shadow to half the width of the original // View. width = getView().getWidth() / 2; // Set the height of the shadow to half the height of the original // View. height = getView().getHeight() / 2; // The drag shadow is a ColorDrawable. Set its dimensions to // be the same as the Canvas that the system provides. As a result, // the drag shadow fills the Canvas. shadow.setBounds(0, 0, width, height); // Set the size parameter's width and height values. These get back // to the system through the size parameter. size.set(width, height); // Set the touch point's position to be in the middle of the drag // shadow. touch.set(width / 2, height / 2); } // Define a callback that draws the drag shadow in a Canvas that the system // constructs from the dimensions passed to onProvideShadowMetrics(). @Override public void onDrawShadow(Canvas canvas) { // Draw the ColorDrawable on the Canvas passed in from the system. shadow.draw(canvas); } }
الاستجابة لبداية السحب
أثناء عملية السحب، يرسل النظام أحداث السحب إلى مستمعي أحداث السحب لعناصر View
في التنسيق الحالي. يتفاعل المستمعون من خلال استدعاء DragEvent.getAction()
للحصول على نوع الإجراء. في بداية السحب،
تعرض هذه الطريقة ACTION_DRAG_STARTED
.
استجابةً لحدث من نوع الإجراء ACTION_DRAG_STARTED
، يجب أن ينفّذ مستمع حدث السحب ما يلي:
عليك استدعاء
DragEvent.getClipDescription()
واستخدام طرق نوع MIME فيClipDescription
المعروض لمعرفة ما إذا كان بإمكان المستمع قبول البيانات التي يتم سحبها.إذا كانت عملية السحب والإفلات لا تمثل حركة البيانات، فقد لا يكون ذلك ضروريًا.
إذا كان بإمكان أداة معالجة حدث السحب قبول عملية الإفلات، يجب أن تعرض السياسة
true
لإبلاغ النظام بمواصلة إرسال أحداث السحب إلى المستمع. إذا لم يقبل المستمع الإفلات، على المستمع عرضfalse
، ويتوقّف النظام عن إرسال أحداث السحب إلى المستمع إلى أن يرسل النظامACTION_DRAG_ENDED
لإنهاء عملية السحب والإفلات.
بالنسبة إلى حدث ACTION_DRAG_STARTED
، تكون طرق DragEvent
التالية غير
صالحة: getClipData()
وgetX()
وgetY()
وgetResult()
.
التعامل مع الأحداث أثناء السحب
أثناء إجراء السحب، تستمر مستمعي أحداث السحب التي تعرض الرمز true
استجابةً
لحدث السحب ACTION_DRAG_STARTED
في تلقّي أحداث السحب. تعتمد أنواع
أحداث السحب التي يتلقّاها المستمع أثناء السحب على موقع
ظل السحب ورؤية View
للمستمع. يستخدم المستمعون أحداث السحب
بشكل أساسي لتحديد ما إذا كان عليهم تغيير مظهر View
أم لا.
أثناء إجراء السحب، تعرض الدالة DragEvent.getAction()
قيمة من ثلاث قيم:
ACTION_DRAG_ENTERED
: يتلقّى المستمع نوع إجراء الحدث هذا عندما تدخل نقطة الاتصال، النقطة على الشاشة أسفل إصبع المستخدم أو الماوس، في المربّع المحيط بعنصرView
للمستمع.ACTION_DRAG_LOCATION
: عندما يتلقّى المستمع حدثACTION_DRAG_ENTERED
، يتلقّى حدثACTION_DRAG_LOCATION
جديد في كل مرّة تنتقل فيها نقطة الاتصال إلى أن تتلقّى حدثACTION_DRAG_EXITED
. تعرض الطرقgetX()
وgetY()
الإحداثي X وY لنقطة الاتصال.ACTION_DRAG_EXITED
: يتم إرسال نوع إجراء الحدث هذا إلى المستمع الذي يتلقّىACTION_DRAG_ENTERED
في السابق. يتم إرسال الحدث عندما تنتقل نقطة لمس ظل السحب من داخل مربّع الإحاطة فيView
للمستمع إلى خارج مربّع الإحاطة.
لا تحتاج أداة معالجة حدث السحب إلى التفاعل مع أي من أنواع الإجراءات هذه. وإذا عرض المستمع قيمة إلى النظام، سيتم تجاهلها.
في ما يلي بعض الإرشادات للاستجابة إلى كل نوع من أنواع الإجراءات هذه:
- استجابةً للسمة
ACTION_DRAG_ENTERED
أوACTION_DRAG_LOCATION
، يمكن للمستمع تغيير مظهرView
للإشارة إلى أنّ المشاهدة هي الهدف المحتمل لانخفاض عدد المشاهدات. - يحتوي حدث بنوع الإجراء
ACTION_DRAG_LOCATION
على بيانات صالحة لـgetX()
وgetY()
بما يتوافق مع الموقع الجغرافي لنقطة الاتصال. يمكن للمستمعين استخدام هذه المعلومات لتغيير مظهرView
عند نقطة اللمس أو لتحديد الموضع الدقيق الذي يمكن للمستخدم فيه إطلاق ظل السحب، أي حذف البيانات. - استجابةً لـ
ACTION_DRAG_EXITED
، على المستمع إعادة ضبط أي تغييرات في الظهور يتم تطبيقها استجابةً إلىACTION_DRAG_ENTERED
أوACTION_DRAG_LOCATION
. يشير ذلك إلى المستخدم أنّView
لم يعُد هدفًا قريبًا للانخفاض.
الردّ على الانخفاض المفاجئ
عندما يرفع المستخدم ظل السحب على View
، ويذكر View
في السابق أنّه يمكنه قبول المحتوى الذي يتم سحبه، يرسِل النظام حدث السحب إلى View
بنوع الإجراء ACTION_DROP
.
على أداة معالجة حدث السحب إجراء ما يلي:
عليك استدعاء
getClipData()
للحصول على الكائنClipData
الذي تم توفيره في الأصل في الطلب إلىstartDragAndDrop()
ومعالجة البيانات. إذا كانت عملية السحب والإفلات لا تمثل حركة البيانات، فهذا غير ضروري.يمكنك عرض القيمة المنطقية
true
للإشارة إلى أنّه تمت معالجة الانخفاض المفاجئ بنجاح أو إلىfalse
إذا لم تتم معالجته. وتصبح القيمة المعروضة هي القيمة التي يعرضهاgetResult()
لحدثACTION_DRAG_ENDED
النهائي. إذا لم يرسل النظام حدثACTION_DROP
، ستكون القيمة التي يعرضهاgetResult()
لحدثACTION_DRAG_ENDED
هيfalse
.
بالنسبة إلى حدث ACTION_DROP
، يستخدم getX()
وgetY()
نظام إحداثيات View
الذي يتلقى الانخفاض لعرض الموضعين X وY لنقطة الاتصال في وقت الانخفاض.
يتيح النظام للمستخدم إزالة ظل السحب على View
الذي لا يتلقى مستمع أحداث السحب فيه أحداث السحب. كما يتيح للمستخدم إطلاق ظل السحب فوق المناطق الفارغة من واجهة المستخدم للتطبيق أو فوق مناطق خارج
التطبيق. في جميع هذه الحالات، لا يرسل النظام حدثًا من نوع الإجراء ACTION_DROP
، على الرغم من أنّ النظام يرسل حدث ACTION_DRAG_ENDED
.
الرد على نهاية سحب
وبعد أن يحرر المستخدم ظل السحب مباشرةً، يرسل النظام حدث السحب
بنوع الإجراء ACTION_DRAG_ENDED
إلى جميع أدوات معالجة أحداث السحب
في تطبيقك. ويشير هذا إلى انتهاء عملية السحب والإفلات.
يجب على كل أداة معالجة حدث سحب إجراء ما يلي:
- إذا غيّر المستمع مظهر عنصر
View
أثناء العملية، على المستمع إعادة ضبطView
على المظهر التلقائي. هذا مؤشر مرئي للمستخدم أن العملية قد انتهت. - يمكن للمستمع الاتصال بـ
getResult()
بشكل اختياري لمعرفة المزيد عن العملية. إذا عرض المستمعtrue
استجابة لحدث من نوع الإجراءACTION_DROP
، تعرضgetResult()
القيمةtrue
المنطقية. في جميع الحالات الأخرى، تعرضgetResult()
القيمة المنطقيةfalse
، بما في ذلك عندما لا يرسل النظام حدثACTION_DROP
. - للإشارة إلى اكتمال عملية السحب والإفلات بنجاح،
على المستمع عرض
true
المنطقي إلى النظام.
الرد على أحداث السحب: مثال
يتم استلام جميع أحداث السحب بواسطة طريقة حدث السحب أو أداة معالجة الحدث. مقتطف الرمز التالي هو مثال بسيط على الاستجابة لأحداث السحب:
Kotlin
val imageView = ImageView(this) // Set the drag event listener for the View. imageView.setOnDragListener { v, e -> // Handle each of the expected events. when (e.action) { DragEvent.ACTION_DRAG_STARTED -> { // Determine whether this View can accept the dragged data. if (e.clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { // As an example, apply a blue color tint to the View to // indicate that it can accept data. (v as? ImageView)?.setColorFilter(Color.BLUE) // Invalidate the view to force a redraw in the new tint. v.invalidate() // Return true to indicate that the View can accept the dragged // data. true } else { // Return false to indicate that, during the current drag and // drop operation, this View doesn't receive events again until // ACTION_DRAG_ENDED is sent. false } } DragEvent.ACTION_DRAG_ENTERED -> { // Apply a green tint to the View. (v as? ImageView)?.setColorFilter(Color.GREEN) // Invalidate the view to force a redraw in the new tint. v.invalidate() // Return true. The value is ignored. true } DragEvent.ACTION_DRAG_LOCATION -> // Ignore the event. true DragEvent.ACTION_DRAG_EXITED -> { // Reset the color tint to blue. (v as? ImageView)?.setColorFilter(Color.BLUE) // Invalidate the view to force a redraw in the new tint. v.invalidate() // Return true. The value is ignored. true } DragEvent.ACTION_DROP -> { // Get the item containing the dragged data. val item: ClipData.Item = e.clipData.getItemAt(0) // Get the text data from the item. val dragData = item.text // Display a message containing the dragged data. Toast.makeText(this, "Dragged data is $dragData", Toast.LENGTH_LONG).show() // Turn off color tints. (v as? ImageView)?.clearColorFilter() // Invalidate the view to force a redraw. v.invalidate() // Return true. DragEvent.getResult() returns true. true } DragEvent.ACTION_DRAG_ENDED -> { // Turn off color tinting. (v as? ImageView)?.clearColorFilter() // Invalidate the view to force a redraw. v.invalidate() // Do a getResult() and display what happens. when(e.result) { true -> Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG) else -> Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG) }.show() // Return true. The value is ignored. true } else -> { // An unknown action type is received. Log.e("DragDrop Example", "Unknown action type received by View.OnDragListener.") false } } }
Java
View imageView = new ImageView(this); // Set the drag event listener for the View. imageView.setOnDragListener( (v, e) -> { // Handle each of the expected events. switch(e.getAction()) { case DragEvent.ACTION_DRAG_STARTED: // Determine whether this View can accept the dragged data. if (e.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { // As an example, apply a blue color tint to the View to // indicate that it can accept data. ((ImageView)v).setColorFilter(Color.BLUE); // Invalidate the view to force a redraw in the new tint. v.invalidate(); // Return true to indicate that the View can accept the dragged // data. return true; } // Return false to indicate that, during the current drag and drop // operation, this View doesn't receive events again until // ACTION_DRAG_ENDED is sent. return false; case DragEvent.ACTION_DRAG_ENTERED: // Apply a green tint to the View. ((ImageView)v).setColorFilter(Color.GREEN); // Invalidate the view to force a redraw in the new tint. v.invalidate(); // Return true. The value is ignored. return true; case DragEvent.ACTION_DRAG_LOCATION: // Ignore the event. return true; case DragEvent.ACTION_DRAG_EXITED: // Reset the color tint to blue. ((ImageView)v).setColorFilter(Color.BLUE); // Invalidate the view to force a redraw in the new tint. v.invalidate(); // Return true. The value is ignored. return true; case DragEvent.ACTION_DROP: // Get the item containing the dragged data. ClipData.Item item = e.getClipData().getItemAt(0); // Get the text data from the item. CharSequence dragData = item.getText(); // Display a message containing the dragged data. Toast.makeText(this, "Dragged data is " + dragData, Toast.LENGTH_LONG).show(); // Turn off color tints. ((ImageView)v).clearColorFilter(); // Invalidate the view to force a redraw. v.invalidate(); // Return true. DragEvent.getResult() returns true. return true; case DragEvent.ACTION_DRAG_ENDED: // Turn off color tinting. ((ImageView)v).clearColorFilter(); // Invalidate the view to force a redraw. v.invalidate(); // Do a getResult() and displays what happens. if (e.getResult()) { Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG).show(); } // Return true. The value is ignored. return true; // An unknown action type is received. default: Log.e("DragDrop Example","Unknown action type received by View.OnDragListener."); break; } return false; });
السحب والإفلات في وضع النوافذ المتعددة
تتوافق الأجهزة التي تعمل بالإصدار 7.0 من نظام التشغيل Android (المستوى 24 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث مع وضع النوافذ المتعددة، الذي يتيح للمستخدمين نقل البيانات من تطبيق إلى آخر باستخدام عملية السحب والإفلات. لمزيد من المعلومات، يُرجى الاطّلاع على إتاحة النوافذ المتعددة.
يقدِّم التطبيق المصدر، حيث تبدأ عملية السحب والإفلات، البيانات. يتلقى التطبيق المستهدف البيانات حيث تنتهي عملية السحب والإفلات.
عند بدء عملية السحب والإفلات، يجب أن يضبط التطبيق المصدر علامة
DRAG_FLAG_GLOBAL
للإشارة إلى أنّه يمكن للمستخدم سحب البيانات إلى تطبيق آخر.
ولأنّ البيانات تتحرك عبر حدود التطبيق، تشارك التطبيقات الوصول إلى البيانات باستخدام معرّف موارد منتظم (URI) للمحتوى. وهذا يتطلّب ما يلي:
- يجب أن يضبط التطبيق المصدر إحدى علامتَي
DRAG_FLAG_GLOBAL_URI_READ
وDRAG_FLAG_GLOBAL_URI_WRITE
أو كليهما، استنادًا إلى إذن الوصول للقراءة أو الكتابة إلى البيانات التي يريد التطبيق المصدر منحها للتطبيق المستهدَف. - يجب أن يطلب التطبيق المستهدَف الرمز
requestDragAndDropPermissions()
مباشرةً قبل معالجة البيانات التي يسحبها المستخدم إلى التطبيق. إذا لم يعد التطبيق الهدف بحاجة إلى الوصول إلى بيانات السحب والإفلات، يمكن للتطبيق بعد ذلك استدعاءrelease()
للكائن الذي تم عرضه منrequestDragAndDropPermissions()
. وبخلاف ذلك، يتم تحرير الأذونات عند تدمير النشاط الذي يحتوي عليه. إذا كانت عملية التنفيذ تتضمّن بدء نشاط جديد لمعالجة عناوين URL التي تم إسقاطها، ستحتاج إلى منح النشاط الجديد الأذونات نفسها. يجب تعيين بيانات المقطع وعلامة:Kotlin
intent.setClipData(clipData) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
Java
intent.setClipData(clipData); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
توضح مقتطفات الرمز التالية كيفية إصدار حق الوصول للقراءة فقط لسحب البيانات وإفلاتها مباشرةً بعد إجراء عملية السحب والإفلات. اطّلع على نموذج DrragAndDrop على GitHub للحصول على مثال أكثر اكتمالاً.
نشاط سحب وإفلات المصدر
Kotlin
// Drag a file stored in an images/ directory in internal storage. val internalImagesDir = File(context.filesDir, "images") val imageFile = File(internalImagesDir, imageFilename) val uri = FileProvider.getUriForFile(context, contentAuthority, imageFile) val listener = OnDragStartListener@{ view: View, _: DragStartHelper -> val clipData = ClipData(ClipDescription("Image Description", arrayOf("image/*")), ClipData.Item(uri)) // Must include DRAG_FLAG_GLOBAL to permit dragging data between apps. // This example provides read-only access to the data. val flags = View.DRAG_FLAG_GLOBAL or View.DRAG_FLAG_GLOBAL_URI_READ return@OnDragStartListener view.startDragAndDrop(clipData, View.DragShadowBuilder(view), null, flags) } // Container where the image originally appears in the source app. val srcImageView = findViewById<ImageView>(R.id.imageView) // Detect and start the drag event. DragStartHelper(srcImageView, listener).apply { attach() }
Java
// Drag a file stored in an images/ directory in internal storage. File internalImagesDir = new File(context.getFilesDir(), "images"); File imageFile = new File(internalImagesDir, imageFilename); final Uri uri = FileProvider.getUriForFile(context, contentAuthority, imageFile); // Container where the image originally appears in the source app. ImageView srcImageView = findViewById(R.id.imageView); // Enable the view to detect and start the drag event. new DragStartHelper(srcImageView, (view, helper) -> { ClipData clipData = new ClipData(new ClipDescription("Image Description", new String[] {"image/*"}), new ClipData.Item(uri)); // Must include DRAG_FLAG_GLOBAL to permit dragging data between apps. // This example provides read-only access to the data. int flags = View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ; return view.startDragAndDrop(clipData, new View.DragShadowBuilder(view), null, flags); }).attach();
نشاط السحب والإفلات المستهدف
Kotlin
// Container where the image is to be dropped in the target app. val targetImageView = findViewById<ImageView>(R.id.imageView) targetImageView.setOnDragListener { view, event -> when (event.action) { ACTION_DROP -> { val imageItem: ClipData.Item = event.clipData.getItemAt(0) val uri = imageItem.uri // Request permission to access the image data being dragged into // the target activity's ImageView element. val dropPermissions = requestDragAndDropPermissions(event) (view as ImageView).setImageURI(uri) // Release the permission immediately afterward because it's no // longer needed. dropPermissions.release() return@setOnDragListener true } // Implement logic for other DragEvent cases here. // An unknown action type is received. else -> { Log.e("DragDrop Example", "Unknown action type received by View.OnDragListener.") return@setOnDragListener false } } }
Java
// Container where the image is to be dropped in the target app. ImageView targetImageView = findViewById(R.id.imageView); targetImageView.setOnDragListener( (view, event) -> { switch (event.getAction()) { case ACTION_DROP: ClipData.Item imageItem = event.getClipData().getItemAt(0); Uri uri = imageItem.getUri(); // Request permission to access the image data being dragged into // the target activity's ImageView element. DragAndDropPermissions dropPermissions = requestDragAndDropPermissions(event); ((ImageView)view).setImageURI(uri); // Release the permission immediately afterward because it's no // longer needed. dropPermissions.release(); return true; // Implement logic for other DragEvent cases here. // An unknown action type was received. default: Log.e("DragDrop Example","Unknown action type received by View.OnDragListener."); break; } return false; });
DropHelper للسحب والإفلات المبسّط
تعمل فئة DropHelper
على تبسيط
تنفيذ إمكانات السحب والإفلات. عضو في مكتبة Jetpack
DragAndDrop
، DropHelper
يوفّر توافقًا مع الأنظمة القديمة وصولاً إلى المستوى 24 من واجهة برمجة التطبيقات.
استخدِم DropHelper
لتحديد أهداف الإفلات وتخصيص تمييز الهدف
وتحديد طريقة التعامل مع البيانات التي تم إفلاتها.
تحديد أهداف الإفلات
DropHelper.configureView()
هي طريقة ثابتة ومحمّلة بشكل زائد تتيح لك تحديد أهداف إفلات. وتشمل معلماته ما يلي:
Activity
الحالي: يتم استخدامه لأذونات معرّف الموارد المنتظم (URI).- تمثّل هذه السمة
View
بصفتها هدفًا لانخفاض عدد الزيارات.- أنواع MIME التي يمكن أن يقبلها هدف الانخفاض من البيانات التي تم إسقاطها.
- تمثّل هذه السمة
- خيارات الضبط لهدف الإفلات، على وجه التحديد، قائمة
بحقول
EditText
المضمّنة - أداة
OnReceiveContentListener
للتعامل مع البيانات المسقطة
على سبيل المثال، لإنشاء هدف إفلات يقبل الصور، استخدِم إحدى الطريقتين التاليتين لإجراء استدعاءات:
Kotlin
configureView( myActivity, targetView, arrayOf("image/*"), options, onReceiveContentListener) // or configureView( myActivity, targetView, arrayOf("image/*"), onReceiveContentListener)
Java
DropHelper.configureView( myActivity, targetView, new String[] {"image/*"}, options, onReceiveContentlistener); // or DropHelper.configureView( myActivity, targetView, new String[] {"image/*"}, onReceiveContentlistener);
يتجاهل الاستدعاء الثاني خيارات إعداد هدف الإفلات، وفي هذه الحالة يتم ضبط لون تمييز الهدف
الإفلات على اللون الثانوي (أو التمييز) للمظهر،
وضبط نصف قطر زاوية التمييز على 16 وحدة بكسل مستقلة الكثافة، وتكون قائمة مكوّنات EditText
فارغة. راجِع القسم التالي للحصول على التفاصيل.
ضبط أهداف الإفلات
تتيح لك الفئة الداخلية DropHelper.Options
ضبط أهداف الإفلات. قدم مثيلاً للفئة إلى الطريقة
DropHelper.configureView(Activity, View, String[], Options,
OnReceiveContentListener
). راجِع القسم السابق للحصول على مزيد من المعلومات.
تخصيص إبراز هدف الإفلات
وتضبط DropHelper
أهداف الإفلات لعرض نص مميّز بينما يسحب المستخدمون المحتوى فوق الأهداف. DropHelper
يوفر النمط التلقائي، ويسمح لك DropHelper.Options
بضبط لون التمييز وتحديد
نصف قطر الزاوية لمستطيل التمييز.
استخدِم الفئة
DropHelper.Options.Builder
لإنشاء مثيل DropHelper.Options
وضبط خيارات الضبط،
كما هو موضّح في المثال التالي:
Kotlin
val options: DropHelper.Options = DropHelper.Options.Builder() .setHighlightColor(getColor(R.color.purple_300)) .setHighlightCornerRadiusPx(resources.getDimensionPixelSize(R.dimen.drop_target_corner_radius)) .build()
Java
DropHelper.Options options = new DropHelper.Options.Builder() .setHighlightColor(getColor(R.color.purple_300)) .setHighlightCornerRadiusPx(getResources().getDimensionPixelSize(R.dimen.drop_target_corner_radius)) .build();
معالجة مكونات EditText في أهداف الإفلات
تتحكّم DropHelper
أيضًا في التركيز ضمن هدف الانخفاض عندما يحتوي الهدف على حقول نصية قابلة للتعديل.
يمكن أن تكون استهدافات الإفلات هي مرة مشاهدة واحدة أو تسلسلاً هرميًا لطريقة العرض. إذا كان التدرّج الهرمي لطريقة الإفلات المستهدفة
يحتوي على مكوِّن واحد أو أكثر من
مكوّنات EditText
،
قدِّم قائمة بالمكوّنات إلى
DropHelper.Options.Builder.addInnerEditTexts(EditText...)
لضمان عمل ميزة تمييز الهدف المستهدَف ومعالجة بيانات النص بشكلٍ صحيح.
تمنع علامة DropHelper
مكوِّنات EditText
ضمن التدرّج الهرمي للعرض المستهدَف للإفلات من سرقة التركيز من العرض الذي يتضمّنه أثناء تفاعلات السحب.
بالإضافة إلى ذلك، إذا كان رمز السحب والإفلات ClipData
يتضمّن بيانات نص ومعرّف موارد منتظم (URI)، يختار DropHelper
أحد مكوّنات EditText
في هدف الإفلات لمعالجة بيانات النص. يعتمد التحديد على الترتيب التالي للأسبقية:
- تمثّل هذه السمة
EditText
الذي يتم إسقاطClipData
عليه. - علامة
EditText
التي تحتوي على مؤشر النص (علامة الإقحام). - تم توفير أول
EditText
للمكالمة إلىDropHelper.Options.Builder.addInnerEditTexts(EditText...)
.
لضبط EditText
كمعالج تلقائي للبيانات النصية، اضبط EditText
على أنّها الوسيطة الأولى لاستدعاء الترميز DropHelper.Options.Builder.addInnerEditTexts(EditText...)
. على سبيل المثال، إذا كان هدف الإفلات يعالج الصور ولكنه يحتوي على حقول نصية قابلة للتعديل T1
وT2
وT3
، اجعل T2
الإعداد التلقائي على النحو التالي:
Kotlin
val options: DropHelper.Options = DropHelper.Options.Builder() .addInnerEditTexts(T2, T1, T3) .build()
Java
DropHelper.Options options = new DropHelper.Options.Builder() .addInnerEditTexts(T2, T1, T3) .build();
معالجة البيانات في أهداف الانخفاض
تقبل الطريقة DropHelper.configureView()
عنصر OnReceiveContentListener
الذي تنشئه للتعامل مع عملية السحب والإفلات ClipData
. يتم توفير بيانات السحب والإفلات
للمستمع في كائن ContentInfoCompat
.
توجد بيانات نصية في الكائن. يتم تمثيل الوسائط، مثل الصور،
بمعرّفات الموارد المنتظمة (URI).
تعالج OnReceiveContentListener
أيضًا البيانات المقدَّمة لهدف الإفلات من خلال تفاعلات المستخدم بخلاف السحب والإفلات، مثل النسخ واللصق، عند استخدام DropHelper.configureView()
لضبط أنواع طرق العرض التالية:
- كل المشاهدات، إذا كان المستخدم يعمل بالإصدار 12 من نظام التشغيل Android أو إصدار أحدث
AppCompatEditText
، إذا كان المستخدم يعمل بإصدار نظام التشغيل Android وصولاً إلى الإصدار 7.0 من نظام التشغيل Android.
أنواع MIME والأذونات والتحقق من المحتوى
يعتمد التحقّق من نوع MIME من قِبل DropHelper
على طريقة السحب والإفلات
ClipDescription
التي ينشئها التطبيق الذي يوفّر بيانات السحب والإفلات. تحقَّق من صحة ClipDescription
لضمان ضبط أنواع MIME بشكلٍ صحيح.
يطلب DropHelper
جميع أذونات الوصول لمعرّفات الموارد المنتظمة (URI) للمحتوى المضمّنة في ClipData
للسحب والإفلات. ولمزيد من المعلومات، يمكنك الاطّلاع على DragAndDropPermissions
. تتيح لك الأذونات حل عناوين URI للمحتوى عند معالجة بيانات السحب والإفلات.
لا يتحقّق DropHelper
من صحة البيانات التي يعرضها موفّرو المحتوى عند حلّ معرّفات الموارد المنتظمة (URI) في البيانات التي تم إسقاطها. تحقق من عدم وجود قيمة فارغة وتحقق
من صحة أي بيانات تم حلها.