چارچوب drag and drop در اندروید به کاربران شما اجازه میدهد تا دادهها را از یک view به view دیگری در طرحبندی فعلی با استفاده از حرکت کشیدن و رها کردن گرافیکی منتقل کنند. از API 11، کشیدن و رها کردن view بر روی سایر viewها یا ViewGroup پشتیبانی میشود. این چارچوب شامل سه مؤلفه مهم زیر برای پشتیبانی از قابلیت کشیدن و رها کردن است:
- کلاس رویداد drag
- listenerهای drag
- متدها و کلاس های کمکی
فرآیند drag و drop کردن
اساساً چهار مرحله یا حالت در فرآیند کشیدن و رها کردن وجود دارد:
- شروع : این رویداد زمانی رخ میدهد که شما شروع به کشیدن یک آیتم در یک طرح میکنید، برنامه شما متد startDrag() را فراخوانی میکند تا به سیستم بگوید کشیدن را شروع کند. آرگومانهای داخل متد startDrag دادههایی را که باید کشیده شوند، ابردادههای این دادهها و یک فراخوان برای ترسیم سایه کشیدن ارائه میکنند.
- ادامه داشتن : کاربر view را انتخاب و به کشیدن ادامه می دهد. سیستم اقدام ACTION_DRAG_ENTERED و به دنبال آن اقدام ACTION_DRAG_LOCATION را به listener رویداد کشیدن viewی که ویو به داخل آن کشیده میشود ارسال میکند. listener ممکن است ظاهر شی View خود را در پاسخ به رویداد تغییر دهد یا می تواند با برجسته کردن نمای آن واکنش نشان دهد. listener رویداد کشیدن یک کنش ACTION_DRAG_EXITED پس از اینکه کاربر سایه کشیدن را به خارج از کادر محدود View منتقل کرد دریافت می کند.
- رها کردن : کاربر, مورد کشیده شده را در کادر محدود یک View رها می کند و سیستم به listener شی View یک رویداد کشیدن با نوع عمل ACTION_DROP می فرستد.
- پایان : درست پس از نوع عمل ACTION_DROP، سیستم یک رویداد کشیدن با نوع عمل ACTION_DRAG_ENDED ارسال میکند تا نشان دهد که عملیات کشیدن به پایان رسیده است.
کلاس DragEvent
DragEvent نشان دهنده رویدادی است که توسط سیستم در زمان های مختلف در طول عملیات کشیدن و رها کردن ارسال می شود. این کلاس مقدار کمی ثابت و متدهای مهمی را ارائه می دهد که ما در طول فرآیند Drag/Drop استفاده می کنیم.
ثابت ها
در زیر تمام اعداد صحیح ثابت موجود به عنوان بخشی از کلاس DragEvent آمده است و هر کدام را بررسی کرده ایم.
ثابت و توضیحات | ردیف |
ACTION_DRAG_STARTED
سیگنال شروع یک عملیات کشیدن و رها کردن را نشان می دهد. |
1 |
ACTION_DRAG_ENTERED
به یک View سیگنال می دهد که نقطه درگ وارد کادر مرزی View شده است. |
2 |
ACTION_DRAG_LOCATION
اگر سایه کشیدن همچنان در کادر محدود شی View باشد، پس از ACTION_DRAG_ENTERED به View ارسال میشود. |
3 |
ACTION_DRAG_EXITED
سیگنال هایی را نشان می دهد که کاربر سایه کشیدن را به خارج از کادر محدود View منتقل کرده است.
|
4 |
ACTION_DROP
به یک View سیگنال می دهد که کاربر سایه کشیدن را آزاد کرده است و نقطه درگ در کادر مرزی View است. |
5 |
ACTION_DRAG_ENDED
به یک View سیگنال می دهد که عملیات drag and drop به پایان رسیده است. |
6 |
متدها
در زیر چند متد مهم و پرکاربرد موجود به عنوان بخشی از کلاس DragEvent آورده شده است.
متد و توضیحات | ردیف |
int getAction() آخرین عمل رویداد انجام شده را مشخص و آن را برمیگرداند. |
1 |
ClipData getClipData() شی ClipData ارسال شده به سیستم را مشخص و آن را برمیگرداند. |
2 |
ClipDescription getClipDescription() شی ClipDescription موجود در ClipData پیدا میکند و آن را برمی گرداند. |
3 |
boolean getResult() نتیجه عملیات را بررسی میکند و آن را برمیگرداند. |
4 |
float getX() مختصات X نقطه درگ را دریافت میکند و آن را برمیگرداند. |
5 |
float getY() مختصات Y نقطه درگ را بدست می آورد و آن را برمیگرداند. |
6 |
String toString() DragEvent را به رشته ای که قابل خواندن باشد تبدیل میکند و آن را برمی گرداند. |
7 |
شنود و پارز رویداد Drag
اگر میخواهید هر یک از viewهای شما در یک Layout به رویداد Drag پاسخ دهد، view شما باید View.OnDragListener را پیادهسازی کند یا متد پاسخ به تماس onDragEvent(DragEvent) را override کند. هنگامی که سیستم متد یا listener را فراخوانی می کند و یک شی DragEvent که در بالا توضیح داده شده است را به آنها ارسال می کند. شما می توانید هم یک listener و هم یک متد برگشت به تماس برای آبجکت View داشته باشید. در هنگام رخ دادن این رویداد، سیستم ابتدا listener را فراخوانی میکند و سپس یک متد callback مشخص میکند و تا زمانی که listener مقدار true را برگرداند آن را فراخوانی میکند.
ترکیب متد onDragEvent(DragEvent) و View.OnDragListener مشابه ترکیب onTouchEvent() و View.OnTouchListener است که برای رویدادهای لمسی در نسخه های قدیمی اندروید استفاده میشود.
شروع و اجرای یک رویداد Drag
شما با ایجاد یک ClipData و ClipData.Item میتوانید انتقال را شروع کنید. با استفاده از بخشی از شی ClipData، ابردادههایی را تهیه کنید که در یک شی ClipDescription در ClipData ذخیره میشوند. برای عملیات drap and drop که حرکت را نشان نمیدهد, ممکن است مقدار null را در عوض یک شی واقعی دریافت کنید.
سپس میتوانید View.DragShadowBuilder را گسترش دهید تا سایهای برای کشیدن view ایجاد کنید. یا به سادگی میتوانید از متد View.DragShadowBuilder(View) برای ایجاد یک سایه پیشفرض درگ به اندازه آرگومان View که به آن ارسال شده است، ایجاد کنید.
مثال
مثال زیر عملکرد یک Drag and Drop ساده را با استفاده از View.setOnLongClickListener() View.setOnTouchListener و View.OnDragEventListener() نشان می دهد.
قدم و توضیحات | مرحله |
ابتدا یک پروژه جدید در اندروید استودیو با یک پکیج دلخواه ایجاد کنید و ادامه مراحل را دنبال کنید. | 1 |
کدهای درون فایل MainActivity.class را مطابق کدهای که در پایین وجود دارد تغییر بدهید. | 2 |
کدهای درون فایل activity_main.xml را مطابق کدهای که در پایین وجود دارد تغییر بدهید. | 3 |
برنامه را بر روی یک تلفن واقعی یا شبیه ساز اجرا کنید و تست را انجام بدهید. | 4 |
کدهای فایل MainActivity.java
package com.seven.cloner.articleslib; import androidx.appcompat.app.AppCompatActivity; import android.content.ClipData; import android.content.ClipDescription; import android.os.Bundle; import android.util.Log; import android.view.DragEvent; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; public class MainActivity extends AppCompatActivity { private final String msg = "7CLONER:"; private ImageView img; private android.widget.RelativeLayout.LayoutParams layoutParams; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); img= findViewById(R.id.imageView); img.setOnLongClickListener(v -> { ClipData.Item item = new ClipData.Item((CharSequence)v.getTag()); String[] mimeTypes = {ClipDescription.MIMETYPE_TEXT_PLAIN}; ClipData dragData = new ClipData(v.getTag().toString(),mimeTypes, item); View.DragShadowBuilder myShadow = new View.DragShadowBuilder(img); v.startDrag(dragData,myShadow,null,0); return true; }); img.setOnDragListener((v, event) -> { switch(event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: layoutParams = (RelativeLayout.LayoutParams)v.getLayoutParams(); Log.d(msg, "Action => DragEvent.ACTION_DRAG_STARTED"); // Do nothing break; case DragEvent.ACTION_DRAG_ENTERED: Log.d(msg, "Action => DragEvent.ACTION_DRAG_ENTERED"); int x_cord = (int) event.getX(); int y_cord = (int) event.getY(); break; case DragEvent.ACTION_DRAG_EXITED : Log.d(msg, "Action => DragEvent.ACTION_DRAG_EXITED"); x_cord = (int) event.getX(); y_cord = (int) event.getY(); layoutParams.leftMargin = x_cord; layoutParams.topMargin = y_cord; v.setLayoutParams(layoutParams); break; case DragEvent.ACTION_DRAG_LOCATION : Log.d(msg, "Action => DragEvent.ACTION_DRAG_LOCATION"); x_cord = (int) event.getX(); y_cord = (int) event.getY(); break; case DragEvent.ACTION_DRAG_ENDED : Log.d(msg, "Action => DragEvent.ACTION_DRAG_ENDED"); // Do nothing break; case DragEvent.ACTION_DROP: Log.d(msg, "ACTION_DROP event"); // Do nothing break; default: break; } return true; }); img.setOnTouchListener((v, event) -> { if (event.getAction() == MotionEvent.ACTION_DOWN) { ClipData data = ClipData.newPlainText("", ""); View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(img); img.startDrag(data, shadowBuilder, img, 0); img.setVisibility(View.INVISIBLE); return true; } else { return false; } }); } }
فایل activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:text="Drag and Drop مثال" android:textSize="30dp" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/textView" android:layout_centerHorizontal="true" android:text="7Cloner.com" android:textColor="#009688" android:textSize="30dp" /> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/textView2" android:layout_alignStart="@+id/textView2" android:layout_alignEnd="@+id/textView2" android:contentDescription="@string/empty" android:src="@drawable/abc" /> </RelativeLayout>
اکنون روی لوگوی 7CLONER کلیک کنید و آن را رها نکنید. خواهید دید که تصویر لوگو کمی بعد از یک کلیک طولانی از جای خود حرکت می کند و حالا میتوانید آنرا جابجا کنید. می توانید آن را در اطراف صفحه بکشید و در مکانی جدید رها کنید.