मुख्य सिद्धांत

'लिखें' सुविधा आज़माएं
Android के लिए, Jetpack Compose को यूज़र इंटरफ़ेस (यूआई) टूलकिट के तौर पर सुझाया जाता है. Compose में, खींचकर छोड़ने की सुविधा का इस्तेमाल करने का तरीका जानें.

इन सेक्शन में, खींचकर छोड़ने की प्रोसेस के कुछ मुख्य कॉन्सेप्ट के बारे में बताया गया है.

खींचें और छोड़ें सुविधा

'खींचें और छोड़ें' प्रोसेस में चार चरण या स्थितियां होती हैं: शुरू की गई, जारी है, छोड़ी गई, और खत्म हो गई.

शुरू किया गया

उपयोगकर्ता के खींचने के जेस्चर के जवाब में, आपका ऐप्लिकेशन startDragAndDrop() को कॉल करता है, ताकि सिस्टम को खींचने और छोड़ने की कार्रवाई शुरू करने के लिए कहा जा सके. विधेय के आर्ग्युमेंट से ये चीज़ें मिलती हैं:

  • जिस डेटा को खींचा और छोड़ा जाना है.
  • खींचकर छोड़ने पर दिखने वाली परछाई को ड्रॉ करने के लिए कॉलबैक
  • खींचे गए डेटा के बारे में बताने वाला मेटाडेटा
  • सिस्टम, ड्रैग शैडो पाने के लिए आपके ऐप्लिकेशन को कॉल करके जवाब देता है. इसके बाद, सिस्टम डिवाइस पर ड्रैग शैडो दिखाता है.
  • इसके बाद, सिस्टम मौजूदा लेआउट में मौजूद सभी View ऑब्जेक्ट के ड्रैग इवेंट के लिसनर को, ऐक्शन टाइप ACTION_DRAG_STARTED वाला ड्रैग इवेंट भेजता है. ड्रैग इवेंट लिसनर को true दिखाना होगा, ताकि ड्रैग इवेंट और ड्रॉप इवेंट की सूचना मिलती रहे. इससे लिसनर को सिस्टम के साथ रजिस्टर किया जाता है. सिर्फ़ रजिस्टर किए गए लिसनर को ही ड्रैग इवेंट मिलते रहेंगे. इस दौरान, दर्शक अपने ड्रॉप टारगेट View ऑब्जेक्ट के दिखने का तरीका भी बदल सकते हैं, ताकि यह दिखाया जा सके कि व्यू में ड्रॉप इवेंट स्वीकार किया जा सकता है.
  • अगर ड्रैग इवेंट के लिसनर से false मिलता है, तो मौजूदा कार्रवाई के लिए उसे ड्रैग इवेंट तब तक नहीं मिलते, जब तक सिस्टम कार्रवाई टाइप ACTION_DRAG_ENDED के साथ ड्रैग इवेंट नहीं भेजता. false दिखाकर, listener, सिस्टम को बताता है कि उसे खींचकर छोड़ने की सुविधा में दिलचस्पी नहीं है और वह खींचे गए डेटा को स्वीकार नहीं करना चाहता.
प्रोसेस जारी है
उपयोगकर्ता, आइटम को खींचकर छोड़ता है. जब ड्रैग शैडो, ड्रॉप टारगेट के बाउंडिंग बॉक्स से इंटरसेक्शन करता है, तो सिस्टम टारगेट के ड्रैग इवेंट लिसनर को एक या उससे ज़्यादा ड्रैग इवेंट भेजता है. इवेंट के जवाब में, लिसनर ड्रॉप टारगेट View के दिखने के तरीके में बदलाव कर सकता है. उदाहरण के लिए, अगर इवेंट से पता चलता है कि ड्रैग किया गया शैडो, ड्रॉप टारगेट के बाउंडिंग बॉक्स में जा रहा है—कार्रवाई का टाइप ACTION_DRAG_ENTERED —तो दर्शक View को हाइलाइट करके प्रतिक्रिया दे सकता है.
प्रेषित
उपयोगकर्ता, ड्रॉप टारगेट के बाउंडिंग बॉक्स में, खींचे गए आइटम को छोड़ देता है. सिस्टम, ड्रॉप टारगेट के लिसनर को ऐक्शन टाइप ACTION_DROP वाला ड्रैग इवेंट भेजता है. ड्रैग इवेंट ऑब्जेक्ट में वह डेटा होता है जो startDragAndDrop() को कॉल करने पर सिस्टम को भेजा जाता है. इससे ऑपरेशन शुरू होता है. अगर listener, ड्रॉप किए गए डेटा को सही तरीके से प्रोसेस करता है, तो उसे सिस्टम को बूलियन true दिखाना चाहिए. : यह चरण सिर्फ़ तब होता है, जब उपयोगकर्ता खींचे गए आइटम के शैडो को किसी ऐसे View के बाउंडिंग बॉक्स में छोड़ता है जिसका लिसनर, खींचे जाने के इवेंट (ड्रॉप टारगेट) पाने के लिए रजिस्टर किया गया हो. अगर उपयोगकर्ता किसी दूसरी स्थिति में खींचे गए आइटम को छोड़ता है, तो कोई ACTION_DROP खींचने का इवेंट नहीं भेजा जाता.
खत्म

जब उपयोगकर्ता, ड्रैग किए गए आइटम को छोड़ देता है और सिस्टम

ACTION_DROP कार्रवाई टाइप के साथ एक ड्रैग इवेंट भेजता है. अगर ज़रूरी हो, तो सिस्टम ACTION_DRAG_ENDED कार्रवाई टाइप के साथ एक ड्रैग इवेंट भेजता है, ताकि यह पता चल सके कि ड्रैग-एंड-ड्रॉप ऑपरेशन खत्म हो गया है. ऐसा तब भी किया जाता है, जब उपयोगकर्ता ड्रैग शैडो को कहीं भी छोड़ता है. यह इवेंट, ड्रैग इवेंट पाने के लिए रजिस्टर किए गए हर लिसनर को भेजा जाता है. भले ही, लिसनर को ACTION_DROP इवेंट भी मिले.

इनमें से हर चरण के बारे में ज़्यादा जानकारी, ड्रैग-एंड-ड्रॉप ऑपरेशन सेक्शन में दी गई है.

ड्रैग इवेंट

सिस्टम, DragEvent ऑब्जेक्ट के तौर पर एक ड्रैग इवेंट भेजता है. इसमें एक ऐक्शन टाइप होता है, जो बताता है कि ड्रैग-एंड-ड्रॉप प्रोसेस में क्या हो रहा है. कार्रवाई के टाइप के आधार पर, ऑब्जेक्ट में अन्य डेटा भी हो सकता है.

ड्रैग इवेंट लिसनर को DragEvent ऑब्जेक्ट मिलता है. ऐक्शन टाइप जानने के लिए, दर्शक DragEvent.getAction() पर कॉल करते हैं. DragEvent क्लास में, पहले से तय वैल्यू के हिसाब से छह वैल्यू तय की गई हैं, जिनके बारे में टेबल 1 में बताया गया है:

टेबल 1. DragEvent के ऐक्शन टाइप

कार्रवाई का टाइप मतलब
ACTION_DRAG_STARTED ऐप्लिकेशन, startDragAndDrop() को कॉल करता है और ड्रैग शैडो पाता है. अगर Listener को इस कार्रवाई के लिए, खींचने और छोड़ने के इवेंट पाना जारी रखना है, तो उसे सिस्टम को बूलियन 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 पर ड्रैग शैडो को छोड़ता है, तो यह ऐक्शन टाइप नहीं भेजा जाता है. ऐसा तब होता है, जब View के लिए कोई listener रजिस्टर न किया गया हो या उपयोगकर्ता, ड्रैग शैडो को किसी ऐसी चीज़ पर छोड़ता है जो मौजूदा लेआउट का हिस्सा नहीं है.

अगर लिसनर, ड्रॉप को प्रोसेस कर लेता है, तो वह बूलियन true दिखाता है. ऐसा न होने पर, यह वैल्यू दिखानी चाहिए false.

ACTION_DRAG_ENDED सिस्टम, खींचकर छोड़ने की प्रोसेस खत्म कर रहा है. इस तरह के ऐक्शन के लिए, ACTION_DROP इवेंट होना ज़रूरी नहीं है. अगर सिस्टम ACTION_DROP भेजता है, तो ACTION_DRAG_ENDED ऐक्शन टाइप मिलने का मतलब यह नहीं है कि ड्रॉप हो गया है. ACTION_DROP के रिस्पॉन्स में मिली वैल्यू पाने के लिए, लिसनर को getResult() को कॉल करना होगा, जैसा कि टेबल 2 में दिखाया गया है. अगर कोई ACTION_DROP इवेंट नहीं भेजा जाता है, तो getResult() false दिखाता है.

DragEvent ऑब्जेक्ट में वह डेटा और मेटाडेटा भी शामिल होता है जो आपका ऐप्लिकेशन, startDragAndDrop() को कॉल करते समय सिस्टम को उपलब्ध कराता है. कुछ डेटा सिर्फ़ कुछ खास तरह की कार्रवाइयों के लिए मान्य है. इसकी जानकारी टेबल 2 में दी गई है. इवेंट और उनसे जुड़े डेटा के बारे में ज़्यादा जानकारी के लिए, खींचें और छोड़ें सेक्शन देखें.

टेबल 2. कार्रवाई के टाइप के हिसाब से मान्य DragEvent डेटा

getAction()
value
getClipDescription()
value
getLocalState()
value
getX()
value
getY()
value
getClipData()
value
getResult()
value
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 ऑब्जेक्ट होता है. सिस्टम, onProvideShadowMetrics() में दिए गए पैरामीटर से इसे बनाता है. यह तरीका, दिए गए Canvas पर ड्रैग शैडो बनाता है.

परफ़ॉर्मेंस को बेहतर बनाने के लिए, खींचें और छोड़ें सुविधा के शैडो का साइज़ छोटा रखें. किसी एक आइटम के लिए, आइकॉन का इस्तेमाल किया जा सकता है. एक से ज़्यादा आइटम चुनने के लिए, हो सकता है कि आप स्क्रीन पर पूरी इमेज के बजाय, स्टैक में आइकॉन का इस्तेमाल करना चाहें.

ड्रैग इवेंट लिसनर और कॉलबैक के तरीके

View को खींचने और छोड़ने से जुड़े इवेंट, खींचने और छोड़ने से जुड़े इवेंट सुनने वाले उस टूल से मिलते हैं जो View.OnDragListener को लागू करता है या व्यू के onDragEvent() कॉलबैक तरीके से मिलते हैं. जब सिस्टम किसी तरीके या लिसनर को कॉल करता है, तो वह एक DragEvent आर्ग्युमेंट उपलब्ध कराता है.

ज़्यादातर मामलों में, कॉलबैक तरीके के बजाय किसी लिसनर का इस्तेमाल करना बेहतर होता है. यूज़र इंटरफ़ेस डिज़ाइन करते समय, आम तौर पर View क्लास को सब-क्लास नहीं बनाया जाता. हालांकि, कॉलबैक तरीके का इस्तेमाल करने पर, आपको उस तरीके को बदलने के लिए सब-क्लास बनाने पड़ते हैं. इसके मुकाबले, एक लिसनर क्लास लागू की जा सकती है और फिर उसका इस्तेमाल कई अलग-अलग View ऑब्जेक्ट के साथ किया जा सकता है. इसे बिना नाम वाली इनलाइन क्लास या लैम्ब्डा एक्सप्रेशन के तौर पर भी लागू किया जा सकता है. View ऑब्जेक्ट के लिए लिसनर सेट करने के लिए, setOnDragListener() को कॉल करें.

इसके अलावा, onDragEvent() के डिफ़ॉल्ट तरीके को बदला जा सकता है. इसके लिए, आपको कोई दूसरा तरीका लागू नहीं करना होगा. किसी व्यू पर OnReceiveContentListener सेट करें. ज़्यादा जानकारी के लिए, setOnReceiveContentListener() देखें. इसके बाद, onDragEvent() तरीका डिफ़ॉल्ट रूप से ये काम करता है:

  • startDragAndDrop() को कॉल करने पर, true दिखाता है.
  • अगर व्यू में खींचकर छोड़ा गया डेटा छोड़ा जाता है, तो performReceiveContent() कॉल करता है. डेटा को ContentInfo ऑब्जेक्ट के तौर पर, विधि में पास किया जाता है. यह तरीका OnReceiveContentListener को ट्रिगर करता है.

  • अगर खींचकर छोड़े गए डेटा को व्यू में छोड़ा जाता है और OnReceiveContentListener किसी कॉन्टेंट का इस्तेमाल करता है, तो यह फ़ंक्शन 'सही' दिखाता है.

खास तौर पर अपने ऐप्लिकेशन के लिए डेटा मैनेज करने के लिए, OnReceiveContentListener तय करें. एपीआई लेवल 24 तक के साथ काम करने के लिए, OnReceiveContentListener के Jetpack वर्शन का इस्तेमाल करें.

आपके पास View ऑब्जेक्ट के लिए, ड्रैग इवेंट लिसनर और कॉलबैक तरीका हो सकता है. ऐसे में, सिस्टम पहले लिसनर को कॉल करता है. सिस्टम, कॉलबैक मेथड को तब तक कॉल नहीं करता, जब तक कि लिसनर false नहीं दिखाता.

onDragEvent() तरीके और View.OnDragListener का कॉम्बिनेशन, टच इवेंट के साथ इस्तेमाल किए जाने वाले onTouchEvent() और View.OnTouchListener के कॉम्बिनेशन जैसा ही है.