مفاهیم اصلی

امتحان کردن روش 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 تعریف شده‌اند، که در جدول ۱ شرح داده شده‌اند:

جدول ۱. انواع کنش 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 ارسال می‌شود که شنونده در پاسخ به رویداد کشیدن ACTION_DRAG_STARTED، بولی true را برگرداند. اگر کاربر سایه کشیدن را روی View که شنونده آن ثبت نشده است رها کند، یا اگر کاربر سایه کشیدن را روی چیزی که بخشی از چیدمان فعلی نیست رها کند، این نوع کنش ارسال نمی‌شود.

اگر شنونده رها کردن را باموفقیت پردازش کند، مقدار بولی true را برمی‌گرداند. درغیراین‌صورت، باید false را برگرداند.

ACTION_DRAG_ENDED ‫The system is ending the drag-and-drop operation. این نوع کنش لزوماً با رویداد ACTION_DROP پیش‌برده نمی‌شود. اگر سیستم ACTION_DROP ارسال کند، دریافت نوع کنش ACTION_DRAG_ENDED به‌معنای موفقیت‌آمیز بودن رها کردن نیست. شنونده باید getResult() را فراخوانی کند، همان‌طور که در جدول ۲ نشان داده شده است، تا مقداری را که در پاسخ به ACTION_DROP برگردانده می‌شود دریافت کند. اگر رویداد ACTION_DROP ارسال نشود، getResult() false را برمی‌گرداند.

شیء DragEvent همچنین حاوی داده‌ها و فراداده‌هایی است که برنامه شما در تماس با startDragAndDrop() به سیستم ارائه می‌دهد. برخی‌از داده‌ها فقط برای انواع کنش‌های خاصی معتبر است که در جدول ۲ خلاصه شده است. برای اطلاعات بیشتر درباره رویدادها و داده‌های مرتبط با آن‌ها، به بخش عملیات کشیدن و رها کردن مراجعه کنید.

جدول ۲. داده‌های 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 یا ۰ را برمی‌گرداند.

سایه کشیدن

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

به این تصویر سایه کشیدن می‌گویند. آن را با روش‌هایی که برای شیء 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()، مقدار true را برمی‌گرداند.
  • فراخوانی می‌کند performReceiveContent() اگر داده‌های کشیدن و رها کردن در نما رها شود. داده‌ها به‌عنوان شیء ContentInfo به روش منتقل می‌شوند. روش OnReceiveContentListener را فراخوانی می‌کند.

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

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

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

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