মূল ধারণা

কম্পোজ পদ্ধতিটি চেষ্টা করুন
জেটপ্যাক কম্পোজ হলো অ্যান্ড্রয়েডের জন্য প্রস্তাবিত UI টুলকিট। কম্পোজে কীভাবে ড্র্যাগ অ্যান্ড ড্রপ ব্যবহার করতে হয় তা শিখুন।

নিম্নলিখিত অংশে ড্র্যাগ-অ্যান্ড-ড্রপ প্রক্রিয়ার কয়েকটি মূল ধারণা ব্যাখ্যা করা হয়েছে।

ড্র্যাগ-অ্যান্ড-ড্রপ প্রক্রিয়া

ড্র্যাগ-অ্যান্ড-ড্রপ প্রক্রিয়ায় চারটি ধাপ বা অবস্থা রয়েছে: শুরু, চলমান, বাদ দেওয়া এবং সমাপ্ত।

শুরু হয়েছে

ব্যবহারকারীর ড্র্যাগ জেসচারের প্রতিক্রিয়ায়, আপনার অ্যাপ্লিকেশনটি সিস্টেমকে একটি ড্র্যাগ-অ্যান্ড-ড্রপ অপারেশন শুরু করার নির্দেশ দিতে startDragAndDrop() মেথডটি কল করে। মেথডটির আর্গুমেন্টগুলো নিম্নলিখিত বিষয়গুলো প্রদান করে:

  • যে ডেটাগুলো টেনে আনা হবে।
  • ড্র্যাগ শ্যাডো আঁকার জন্য একটি কলব্যাক
  • টেনে আনা ডেটার বর্ণনা দেয় এমন মেটাডেটা
  • সিস্টেমটি একটি ড্র্যাগ শ্যাডো পাওয়ার জন্য আপনার অ্যাপ্লিকেশনে কলব্যাক করে সাড়া দেয়। এরপর সিস্টেমটি ডিভাইসে ড্র্যাগ শ্যাডোটি প্রদর্শন করে।
  • এরপর, সিস্টেম বর্তমান লেআউটের সমস্ত View অবজেক্টের ড্র্যাগ ইভেন্ট লিসেনারে ACTION_DRAG_STARTED অ্যাকশন টাইপের একটি ড্র্যাগ ইভেন্ট পাঠায়। ড্র্যাগ ইভেন্ট—একটি সম্ভাব্য ড্রপ ইভেন্ট সহ—পেতে থাকার জন্য, ড্র্যাগ ইভেন্ট লিসেনারকে অবশ্যই 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 ক্লাসের কনস্ট্যান্ট দ্বারা সংজ্ঞায়িত ছয়টি সম্ভাব্য মান রয়েছে, যা সারণি ১-এ বর্ণনা করা হয়েছে:

সারণি ১. ড্র্যাগইভেন্ট অ্যাকশনের প্রকারভেদ

কর্মের ধরণ অর্থ
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 সিস্টেমটি ড্র্যাগ-অ্যান্ড-ড্রপ অপারেশনটি শেষ করছে। এই অ্যাকশন টাইপটির আগে ACTION_DROP ইভেন্ট থাকা আবশ্যক নয়। যদি সিস্টেম একটি ACTION_DROP ইভেন্ট পাঠায়, তাহলে ACTION_DRAG_ENDED অ্যাকশন টাইপটি পাওয়ার অর্থ এই নয় যে ড্রপটি সফল হয়েছে। ACTION_DROP এর প্রতিক্রিয়ায় যে মানটি ফেরত আসে, তা পাওয়ার জন্য লিসেনারকে অবশ্যই getResult() কল করতে হবে, যেমনটি টেবিল ২- এ দেখানো হয়েছে। যদি কোনো 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 বা 0 রিটার্ন করে।

ড্র্যাগ শ্যাডো

ড্র্যাগ-অ্যান্ড-ড্রপ অপারেশনের সময়, ব্যবহারকারী যে ছবিটি ড্র্যাগ করেন, সিস্টেমটি সেটি প্রদর্শন করে। ডেটা স্থানান্তরের ক্ষেত্রে, এই ছবিটি ড্র্যাগ করা ডেটার প্রতিনিধিত্ব করে। অন্যান্য অপারেশনের জন্য, ছবিটি ড্র্যাগ অপারেশনের কোনো একটি দিকের প্রতিনিধিত্ব করে।

এই ইমেজটিকে ড্র্যাগ শ্যাডো বলা হয়। আপনি একটি View.DragShadowBuilder অবজেক্টের জন্য ঘোষিত মেথডগুলো ব্যবহার করে এটি তৈরি করেন। startDragAndDrop() ব্যবহার করে যখন আপনি একটি ড্র্যাগ-অ্যান্ড-ড্রপ অপারেশন শুরু করেন, তখন আপনি বিল্ডারটিকে সিস্টেমে পাস করেন। startDragAndDrop() এর প্রতিক্রিয়ার অংশ হিসেবে, একটি ড্র্যাগ শ্যাডো পাওয়ার জন্য সিস্টেম আপনার View.DragShadowBuilder এ সংজ্ঞায়িত কলব্যাক মেথডগুলোকে কল করে।

View.DragShadowBuilder ক্লাসের দুটি কনস্ট্রাক্টর আছে:

View.DragShadowBuilder(View)

এই কনস্ট্রাক্টরটি আপনার অ্যাপ্লিকেশনের যেকোনো View অবজেক্ট গ্রহণ করে। কনস্ট্রাক্টরটি View অবজেক্টটিকে View.DragShadowBuilder অবজেক্টে সংরক্ষণ করে, যাতে কলব্যাকগুলো ড্র্যাগ শ্যাডো তৈরি করার জন্য এটিকে অ্যাক্সেস করতে পারে। ড্র্যাগ অপারেশন শুরু করার জন্য ভিউটি ব্যবহারকারীর নির্বাচিত কোনো View হতে হবে এমন কোনো বাধ্যবাধকতা নেই।

আপনি যদি এই কনস্ট্রাক্টরটি ব্যবহার করেন, তাহলে আপনাকে View.DragShadowBuilder এক্সটেন্ড করতে বা এর মেথডগুলো ওভাররাইড করতে হবে না। ডিফল্টরূপে, আপনি আর্গুমেন্ট হিসেবে পাস করা View মতোই দেখতে একটি ড্র্যাগ শ্যাডো পাবেন, যা ব্যবহারকারীর স্ক্রিনে স্পর্শ করা স্থানের ঠিক নিচে কেন্দ্র করে থাকে।

View.DragShadowBuilder()

আপনি যদি এই কনস্ট্রাক্টরটি ব্যবহার করেন, তাহলে View.DragShadowBuilder অবজেক্টে কোনো View অবজেক্ট উপলব্ধ থাকে না। ফিল্ডটি null সেট করা থাকে। আপনাকে অবশ্যই View.DragShadowBuilder এক্সটেন্ড করতে হবে এবং এর মেথডগুলো ওভাররাইড করতে হবে, অন্যথায় আপনি একটি অদৃশ্য ড্র্যাগ শ্যাডো পাবেন। সিস্টেম কোনো এরর দেখায় না।

View.DragShadowBuilder ক্লাসে দুটি মেথড আছে যা একত্রে ড্র্যাগ শ্যাডো তৈরি করে:

onProvideShadowMetrics()

আপনি startDragAndDrop() কল করার ঠিক পরেই সিস্টেম এই মেথডটি কল করে। ড্র্যাগ শ্যাডোর ডাইমেনশন এবং টাচ পয়েন্ট সিস্টেমে পাঠানোর জন্য এই মেথডটি ব্যবহার করুন। মেথডটির দুটি প্যারামিটার রয়েছে:

outShadowSize : একটি Point অবজেক্ট। ড্র্যাগ শ্যাডোর প্রস্থ x অক্ষে এবং উচ্চতা y অক্ষে নির্ধারিত হয়।

outShadowTouchPoint : একটি Point অবজেক্ট। টাচ পয়েন্ট হলো ড্র্যাগ শ্যাডোর ভেতরের সেই অবস্থান, যা ড্র্যাগ করার সময় ব্যবহারকারীর আঙুলের নিচে অবশ্যই থাকতে হবে। এর X অবস্থান x এ এবং Y অবস্থান y এ বসাতে হয়।

onDrawShadow()

onProvideShadowMetrics() কল করার ঠিক পরেই সিস্টেম ড্র্যাগ শ্যাডো তৈরি করার জন্য onDrawShadow() মেথডটি কল করে। এই মেথডটির একটিমাত্র আর্গুমেন্ট থাকে, যা হলো একটি Canvas অবজেক্ট। সিস্টেম এই Canvas অবজেক্টটি তৈরি করে onProvideShadowMetrics() -এ আপনার দেওয়া প্যারামিটারগুলো থেকে। এই মেথডটি প্রদত্ত Canvas উপর ড্র্যাগ শ্যাডোটি অঙ্কন করে।

পারফরম্যান্স উন্নত করতে, ড্র্যাগ শ্যাডোর আকার ছোট রাখুন। একটিমাত্র আইটেমের জন্য আপনি একটি আইকন ব্যবহার করতে পারেন। একাধিক আইটেম নির্বাচনের ক্ষেত্রে, স্ক্রিন জুড়ে সম্পূর্ণ ছবি ছড়িয়ে দেওয়ার পরিবর্তে আপনি আইকনগুলোকে একটির পর একটি সাজিয়ে ব্যবহার করতে পারেন।

ড্র্যাগ ইভেন্ট লিসেনার এবং কলব্যাক পদ্ধতি

একটি View View.OnDragListener ইমপ্লিমেন্ট করা একটি ড্র্যাগ ইভেন্ট লিসেনারের মাধ্যমে অথবা ভিউটির onDragEvent() কলব্যাক মেথডের মাধ্যমে ড্র্যাগ ইভেন্ট গ্রহণ করে। যখন সিস্টেম মেথড বা লিসেনারটিকে কল করে, তখন এটি একটি DragEvent আর্গুমেন্ট প্রদান করে।

বেশিরভাগ ক্ষেত্রে, কলব্যাক মেথড ব্যবহার করার চেয়ে লিসেনার ব্যবহার করা শ্রেয়। UI ডিজাইন করার সময়, আপনি সাধারণত View ক্লাসের সাবক্লাস তৈরি করেন না, কিন্তু কলব্যাক মেথড ব্যবহার করলে মেথডটি ওভাররাইড করার জন্য আপনাকে সাবক্লাস তৈরি করতে হয়। এর তুলনায়, আপনি একটি লিসেনার ক্লাস ইমপ্লিমেন্ট করে একাধিক ভিন্ন View অবজেক্টের সাথে এটি ব্যবহার করতে পারেন। আপনি এটিকে একটি অ্যানোনিমাস ইনলাইন ক্লাস বা ল্যাম্বডা এক্সপ্রেশন হিসেবেও ইমপ্লিমেন্ট করতে পারেন। একটি View অবজেক্টের জন্য লিসেনার সেট করতে, setOnDragListener() কল করুন।

বিকল্প হিসেবে, আপনি মেথডটি ওভাররাইড না করেই onDragEvent() এর ডিফল্ট ইমপ্লিমেন্টেশন পরিবর্তন করতে পারেন। একটি ভিউতে একটি OnReceiveContentListener সেট করুন; আরও বিস্তারিত জানতে setOnReceiveContentListener() দেখুন। এরপর onDragEvent() মেথডটি ডিফল্টভাবে নিম্নলিখিত কাজগুলো করে থাকে:

  • startDragAndDrop() কলের প্রতিক্রিয়ায় true রিটার্ন করে।
  • ভিউ-এর উপর ড্র্যাগ-অ্যান্ড-ড্রপ ডেটা ফেলা হলে performReceiveContent() কল করা হয়। ডেটাটি একটি ContentInfo অবজেক্ট হিসেবে মেথডটিতে পাঠানো হয়। এই মেথডটি OnReceiveContentListener আহ্বান করে।

  • যদি ড্র্যাগ-অ্যান্ড-ড্রপ ডেটা ভিউ-এর উপর ফেলা হয় এবং OnReceiveContentListener সেই কন্টেন্টের কোনো একটি গ্রহণ করে, তাহলে true রিটার্ন করে।

আপনার অ্যাপের জন্য বিশেষভাবে ডেটা পরিচালনা করতে OnReceiveContentListener সংজ্ঞায়িত করুন। API লেভেল 24 পর্যন্ত ব্যাকওয়ার্ড কম্প্যাটিবিলিটির জন্য, OnReceiveContentListener এর Jetpack সংস্করণটি ব্যবহার করুন।

একটি View অবজেক্টের জন্য একটি ড্র্যাগ ইভেন্ট লিসেনার এবং একটি কলব্যাক মেথড থাকতে পারে, সেক্ষেত্রে সিস্টেম প্রথমে লিসেনারটিকে কল করে। লিসেনারটি false রিটার্ন না করলে সিস্টেম কলব্যাক মেথডটি কল করে না।

onDragEvent() মেথড এবং View.OnDragListener এর সমন্বয়টি, টাচ ইভেন্টের ক্ষেত্রে ব্যবহৃত onTouchEvent() এবং View.OnTouchListener এর সমন্বয়ের অনুরূপ।