مفاهیم کلیدی

روش نوشتن را امتحان کنید
Jetpack Compose ابزار رابط کاربری پیشنهادی برای اندروید است. یاد بگیرید که چگونه از کشیدن و رها کردن در Compose استفاده کنید.

بخش‌های بعدی چند مفهوم کلیدی برای فرآیند کشیدن و رها کردن را توضیح می‌دهند.

فرآیند کشیدن و رها کردن

چهار مرحله یا حالت در فرآیند کشیدن و رها کردن وجود دارد: شروع شده، ادامه دار، رها شده و پایان یافته.

شروع شده

در پاسخ به حرکت کشیدن کاربر، برنامه شما تابع startDragAndDrop() را فراخوانی می‌کند تا به سیستم بگوید که عملیات کشیدن و رها کردن را شروع کند. آرگومان‌های این متد موارد زیر را ارائه می‌دهند:

  • داده‌هایی که باید کشیده شوند.
  • فراخوانی برای ترسیم سایه درگ
  • فراداده‌ای که داده‌های کشیده‌شده را توصیف می‌کند
  • سیستم با فراخوانی برنامه شما برای دریافت سایه کشیدن پاسخ می‌دهد. سپس سیستم سایه کشیدن را روی دستگاه نمایش می‌دهد.
  • در مرحله بعد، سیستم یک رویداد کشیدن با نوع اکشن ACTION_DRAG_STARTED را به شنونده رویداد کشیدن همه اشیاء View در طرح فعلی ارسال می‌کند. برای ادامه دریافت رویدادهای کشیدن - از جمله یک رویداد رها کردن احتمالی - شنونده رویداد کشیدن باید true برگرداند. این باعث می‌شود شنونده در سیستم ثبت شود. فقط شنونده‌های ثبت شده همچنان رویدادهای کشیدن را دریافت می‌کنند. در این مرحله، شنونده‌ها می‌توانند ظاهر شیء View هدف رها کردن خود را نیز تغییر دهند تا نشان دهند که 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 را نیز دریافت کند.

هر یک از این مراحل با جزئیات بیشتر در بخشی با عنوان «عملیات کشیدن و رها کردن» شرح داده شده است.

رویدادهای کشیدن

سیستم یک رویداد کشیدن (drag) را به شکل یک شیء DragEvent ارسال می‌کند که شامل یک نوع اکشن است که آنچه را که در فرآیند کشیدن و رها کردن اتفاق می‌افتد، توصیف می‌کند. بسته به نوع اکشن، شیء می‌تواند حاوی داده‌های دیگری نیز باشد.

شنونده‌های رویداد Drag، شیء DragEvent را دریافت می‌کنند. برای دریافت نوع عمل، شنونده‌ها DragEvent.getAction() را فراخوانی می‌کنند. شش مقدار ممکن وجود دارد که توسط ثابت‌های کلاس DragEvent تعریف شده‌اند و در جدول 1 توضیح داده شده‌اند:

جدول 1. انواع اکشن DragEvent

نوع اقدام معنی
ACTION_DRAG_STARTED برنامه تابع startDragAndDrop() را فراخوانی می‌کند و یک سایه‌ی درگ دریافت می‌کند. اگر شنونده بخواهد به دریافت رویدادهای درگ برای این عملیات ادامه دهد، باید مقدار boolean true به سیستم برگرداند.
ACTION_DRAG_ENTERED سایه کشیدن وارد کادر محدوده View شنونده رویداد کشیدن می‌شود. این اولین نوع اقدام رویدادی است که شنونده هنگام ورود سایه کشیدن به کادر محدوده دریافت می‌کند.
ACTION_DRAG_LOCATION پس از رویداد ACTION_DRAG_ENTERED ، سایه‌ی کشیدن هنوز درون کادر محدوده‌ی View مربوط به شنونده‌ی رویداد کشیدن قرار دارد.
ACTION_DRAG_EXITED پس از یک رویداد ACTION_DRAG_ENTERED و حداقل یک رویداد ACTION_DRAG_LOCATION ، سایه‌ی درگ به خارج از کادر محدوده‌ی View مربوط به شنونده‌ی رویداد درگ حرکت می‌کند.
ACTION_DROP سایه کشیدن (drag shadow) روی View مربوط به شنونده رویداد drag آزاد می‌شود. این نوع اکشن فقط در صورتی به شنونده شیء View ارسال می‌شود که شنونده در پاسخ به رویداد drag مربوط ACTION_DRAG_STARTED مقدار boolean true را برگرداند. این نوع اکشن در صورتی ارسال نمی‌شود که کاربر سایه کشیدن را روی 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 را برمی‌گرداند.

سایه را بکشید

در طول عملیات کشیدن و رها کردن، سیستم تصویری را که کاربر می‌کشد نمایش می‌دهد. برای جابجایی داده‌ها، این تصویر نشان‌دهنده داده‌های در حال کشیدن است. برای سایر عملیات، تصویر نشان‌دهنده جنبه‌ای از عملیات کشیدن است.

این تصویر، سایه‌ی کشیدن (drag shadow) نامیده می‌شود. شما آن را با متدهایی که برای شیء View.DragShadowBuilder تعریف می‌کنید، ایجاد می‌کنید. شما سازنده (builder) را هنگام شروع عملیات کشیدن و رها کردن با استفاده از startDragAndDrop() به سیستم ارسال می‌کنید. به عنوان بخشی از پاسخ خود به startDragAndDrop() ، سیستم متدهای فراخوانی (callback) را که در View.DragShadowBuilder تعریف کرده‌اید، برای به دست آوردن سایه‌ی کشیدن، فراخوانی می‌کند.

کلاس View.DragShadowBuilder دو سازنده دارد:

View.DragShadowBuilder(View)

این سازنده هر یک از اشیاء View برنامه شما را می‌پذیرد. سازنده، شیء View را در شیء View.DragShadowBuilder ذخیره می‌کند، بنابراین callbackها می‌توانند برای ساخت سایه drag به آن دسترسی داشته باشند. view لازم نیست View ای باشد که کاربر برای شروع عملیات drag انتخاب می‌کند.

اگر از این سازنده استفاده کنید، لازم نیست 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 رویدادهای drag را با یک شنونده‌ی رویداد drag که View.OnDragListener را پیاده‌سازی می‌کند یا با متد فراخوانی onDragEvent() مربوط به view دریافت می‌کند. وقتی سیستم متد یا شنونده را فراخوانی می‌کند، یک آرگومان DragEvent ارائه می‌دهد.

در بیشتر موارد، استفاده از یک شنونده (listener) نسبت به استفاده از متد callback ارجحیت دارد. هنگام طراحی رابط‌های کاربری، معمولاً از کلاس‌های View زیرکلاس نمی‌سازید، اما استفاده از متد callback شما را مجبور می‌کند تا زیرکلاس‌هایی برای لغو متد ایجاد کنید. در مقابل، می‌توانید یک کلاس شنونده (listener) را پیاده‌سازی کنید و سپس آن را با چندین شیء View مختلف استفاده کنید. همچنین می‌توانید آن را به عنوان یک کلاس درون‌خطی ناشناس یا عبارت lambda پیاده‌سازی کنید. برای تنظیم شنونده برای یک شیء View ، تابع setOnDragListener() را فراخوانی کنید.

به عنوان یک جایگزین، می‌توانید پیاده‌سازی پیش‌فرض onDragEvent() را بدون بازنویسی متد تغییر دهید. یک OnReceiveContentListener روی یک نما تنظیم کنید؛ برای جزئیات بیشتر، به setOnReceiveContentListener() مراجعه کنید. سپس متد onDragEvent() به طور پیش‌فرض موارد زیر را انجام می‌دهد:

  • در پاسخ به فراخوانی تابع startDragAndDrop() مقدار true را برمی‌گرداند.
  • اگر داده‌های حاصل از کشیدن و رها کردن در نما رها شوند، تابع performReceiveContent() فراخوانی می‌شود. داده‌ها به عنوان یک شیء ContentInfo به متد ارسال می‌شوند. متد، OnReceiveContentListener را فراخوانی می‌کند.

  • اگر داده‌های کشیدن و رها کردن روی نما رها شوند و OnReceiveContentListener هر یک از محتوا را مصرف کند، مقدار true را برمی‌گرداند.

OnReceiveContentListener برای مدیریت داده‌ها به طور خاص برای برنامه خود تعریف کنید. برای سازگاری با نسخه‌های قبلی تا سطح API 24، از نسخه Jetpack از OnReceiveContentListener استفاده کنید.

شما می‌توانید یک شنونده‌ی رویداد drag و یک متد callback برای یک شیء View داشته باشید، که در این صورت سیستم ابتدا شنونده را فراخوانی می‌کند. سیستم متد callback را فراخوانی نمی‌کند مگر اینکه شنونده false را برگرداند.

ترکیب متد onDragEvent() و View.OnDragListener مشابه ترکیب onTouchEvent() و View.OnTouchListener است که در رویدادهای لمسی استفاده می‌شود.