Drag-and-Drop — un gest interactiv de tragere a unui obiect vizual pe ecran cu ajutorul degetului. Gestul constă în trei faze: capturare (long press sau atingere), deplasare (mișcarea degetului cu obiectul) și eliberare (aruncare în zona țintă). Este folosit pentru a schimba ordinea elementelor, a muta fișiere între foldere, a organiza interfața (drag to reorder, drag to resize). În iOS se implementează prin UIDragInteraction, în Android — prin DragEvent și startDragAndDrop.
Principalele
Drag-and-Drop (DnD, tragere) — o metodă de manipulare a elementelor grafice ale interfeței în care utilizatorul prinde un obiect cu degetul sau mouse-ul, îl mută în altă poziție și îl eliberează. În interfețele mobile, Drag-and-Drop este de obicei inițiat prin apăsare lungă (Long Press) — utilizatorul ține elementul timp de 300–500 ms, după care sistemul comută interfața în modul de tragere, iar mișcarea degetului deplasează obiectul.
Istoric, Drag-and-Drop a apărut în interfețele desktop (Xerox Star, 1981; Macintosh, 1984) ca alternativă la comenzile copiere/lipire. Pe platformele mobile, suportul complet a apărut în iOS 11 (2017) cu UIDragInteraction și în Android 7.0 (2016) cu Multi-Window Drag-and-Drop. Înainte de aceasta, tragerea în aplicațiile mobile era implementată prin soluții personalizate cu gesture recognizers.
Concepte cheie: drag session (sesiune de tragere), drag items (obiecte trase), drag preview (imaginea vizuală a obiectului), drop target (zona de eliberare), drop proposal (acțiune la eliberare: mutare, copiere, legare). Sistemul gestionează sesiunea la nivelul sistemului de operare, ceea ce permite tragerea obiectelor între diferite aplicații (de exemplu, o fotografie din Galerie în Note).
Drag-and-Drop se împarte în trei faze consecutive. Faza 1 — capturarea (Drag Start): utilizatorul inițiă gestul (de obicei Long Press), sistemul creează o sesiune de tragere, preia datele obiectului și afișează drag preview — o copie semitransparentă a elementului care urmează degetul. În această fază, sistemul respinge alte gesturi (derulare, selectare text) până la finalizarea DnD.
Faza 2 — deplasarea (Drag Move): degetul se mișcă pe ecran, drag preview urmează punctul de atingere. Sistemul determină continuu drop target sub deget și trimite evenimente drag enter, drag move și drag exit. Drop target poate reacționa vizual: să se aprindă, să se extindă sau să arate o linie de inserție. Această fază durează de la 0.5 la 10+ secunde în funcție de complexitatea sarcinii.
Faza 3 — eliberarea (Drop): degetul se ridică de pe ecran. Sistemul încheie sesiunea de tragere și apelează drop callback la elementul țintă. Dacă drop target respinge eliberarea (de exemplu, tragerea unui fișier într-un folder fără drepturi de scriere), drag preview revine animat la poziția originală (cancel animation). Dacă eliberarea este acceptată, elementul dispare din poziția originală și apare în cea țintă.
| Faza | Eveniment iOS | Eveniment Android | Stare vizuală |
|---|---|---|---|
| Capturare | UIDragInteractionDelegate.dragSessionWillBegin | View.OnLongClickListener → startDragAndDrop | Drag preview apare sub deget |
| Deplasare | UIDropInteractionDelegate.dragSessionDidUpdate | View.OnDragListener.onDrag (ACTION_DRAG_MOVED) | Preview se mișcă, target aprins |
| Eliberare | UIDropInteractionDelegate.performDrop | View.OnDragListener.onDrag (ACTION_DROP) | Animația de eliberare sau revenire |
Tragerea între aplicații — funcție disponibilă pe ambele platforme. iOS suportă Drag-and-Drop între aplicații în modul Split View și Slide Over (iPad). Android suportă tragerea între aplicații în modul Split Screen. Datele sunt transmise prin UIPasteConfiguration (iOS) sau ClipData (Android). Dezvoltatorul specifică tipurile de date suportate (UTI pentru iOS, MIME pentru Android).
UIDragInteraction — API-ul principal iOS pentru tragere, adăugat în iOS 11. Pentru a activa tragerea din View, adăugați UIDragInteraction cu UIDragInteractionDelegate. Delegatul determină ce elemente sunt trase, aspectul și comportamentul lor. Pentru primirea elementelor se folosește UIDropInteraction cu UIDropInteractionDelegate, care determină dacă View poate accepta eliberarea și cum să proceseze datele.
// UIDragInteraction — tragerea elementului din colecție
class DragViewController: UIViewController, UIDragInteractionDelegate {
@IBOutlet var dragSourceView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let dragInteraction = UIDragInteraction(delegate: self)
dragSourceView.addInteraction(dragInteraction)
}
func dragInteraction(_ interaction: UIDragInteraction,
itemsForBeginning session: UIDragSession) -> [UIDragItem] {
guard let data = Data(contentsOf: selectedFileURL) else { return [] }
let itemProvider = NSItemProvider(object: data as NSData)
let dragItem = UIDragItem(itemProvider: itemProvider)
// Drag preview — copie redusă a elementului
dragItem.previewProvider = {
let previewView = UIImageView(image: thumbnailImage)
previewView.alpha = 0.8
return UIDragPreview(view: previewView)
}
return [dragItem]
}
}UIDropInteractionDelegate — interfața oglindă pentru primirea eliberării. Metoda canHandle(_:) verifică dacă tipul de date este suportat. sessionDidUpdate(_:) actualizează vizual starea (aprindere, linie de inserție). performDrop(_:) execută procesarea finală a datelor. iOS apelează automat UIDropProposal cu tipul operației: .move (mutare), .copy (copiere), .forbidden (interzis). Tipul operației influențează afișarea vizuală (iconița + în colțul preview pentru copiere, semnul de interzis pentru forbidden).
View.startDragAndDrop() — metoda Android SDK pentru începerea tragerii, disponibilă din API 24 (Android 7.0). Este apelată după capturarea elementului (de obicei în onLongClick). Parametri: ClipData (date), DragShadowBuilder (umbră vizuală), Object myLocalState (stare locală), flags. DragShadowBuilder creează un Bitmap care urmează degetul. Sistemul gestionează automat animația și evenimentele tactile în timpul tragerii.
// Drag-and-Drop elementului RecyclerView cu reordonare
class ReorderAdapter(private val items: MutableList<String>) :
RecyclerView.Adapter<ReorderAdapter.ViewHolder>() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.setOnLongClickListener {
// Creăm ClipData pentru transmiterea datelor
val clipData = ClipData.newPlainText("item", items[position])
// DragShadowBuilder personalizat cu preview redus
val shadowBuilder = object : View.DragShadowBuilder(holder.itemView) {
override fun onProvideShadowMetrics(shadowSize: Point, shadowTouchPoint: Point) {
shadowSize.set(itemView.width, itemView.height / 2)
}
}
holder.itemView.startDragAndDrop(clipData, shadowBuilder, position, 0)
true
}
}
}Primirea eliberării în Android se realizează prin View.setOnDragListener(). Ascultătorul primește evenimentele ACTION_DRAG_STARTED, ACTION_DRAG_ENTERED, ACTION_DRAG_LOCATION, ACTION_DRAG_EXITED, ACTION_DROP, ACTION_DRAG_ENDED. În evenimentul ACTION_DROP, datele sunt extrase din ClipData și se execută acțiunea țintă. Pentru RecyclerView cu reordonare, se recomandă ItemTouchHelper.SimpleCallback — un mecanism încorporat care gestionează automat Long Press pentru capturare, animația deplasării elementelor și metodele utilitare onMove/onSwiped.
Reordonarea listelor (drag to reorder) — cel mai frecvent scenariu DnD: utilizatorul trage elementele listei pentru a le schimba ordinea. Exemple: rearanjarea contactelor favorite, sortarea sarcinilor în trackere (Trello, Todoist), schimbarea ordinii pieselor în playlist (Spotify, Apple Music). Se implementează prin ItemTouchHelper în Android sau UILongPressGestureRecognizer + rearanjarea celulelor în iOS.
Managerii de fișiere — Drag-and-Drop pentru copierea și mutarea fișierelor între foldere. iOS Files App, Android Files by Google, Dropbox — toate suportă DnD. Tragerea unui fișier pe un folder îl mută în interior (move), tragerea cu tasta Option/Ctrl apăsată îl copiază (copy). Drop target se aprinde vizual la apropiere, arătând limitele folderului.
Tablourile Kanban — Trello, Jira, Notion folosesc Drag-and-Drop pentru mutarea cardurilor între coloane (To Do → In Progress → Done). În timpul tragerii, cardul se detașează de coloana sursă, urmează degetul, iar la traversarea graniței altei coloane este inserat cu animație. iOS 11+ suportă UIDragPreview cu efect de paralaxă, unde preview se abate ușor de la punctul de atingere, creând profunzime.
Secțiunile Springboard (iOS) — tragerea pictogramelor aplicațiilor pe ecranul principal iOS. Apăsarea lungă pe o pictogramă activează modul „jiggling” (pictogramele tremură), după care utilizatorul poate muta pictogramele între pagini și poate crea foldere. Acesta este unul dintre cele mai complexe modele UX DnD, deoarece necesită gestionarea simultană a tragerii, animației de tremur și grupării în foldere.
Feedback vizual — critic pentru Drag-and-Drop. Obiectul tras trebuie să se schimbe: să se micșoreze (iOS: scale 0.8–0.9), să devină semitransparent (alpha 0.7–0.8) și să se ridice deasupra interfeței cu umbră (shadow offset). Drop target trebuie să reacționeze vizual la apropiere: să se aprindă (highlight), să se extindă (expand) sau să arate margini (border). Fără aceste semnale, utilizatorul nu înțelege unde poate elibera obiectul.
Animația de revenire (drag cancel) — dacă utilizatorul eliberează elementul în afara zonei de eliberare sau deasupra unei zone invalide, obiectul trebuie să revină animat la poziția originală. iOS UIDragInteractionDelegate oferă dragInteraction(_:sessionDidMove:) pentru urmărire și dragInteraction(_:session:willEndWith:) pentru animația de revenire. Android View.setOnDragListener primește ACTION_DRAG_ENDED, unde se poate porni animația de revenire prin ValueAnimator sau ObjectAnimator.
| Recomandare | iOS | Android |
|---|---|---|
| Capturare cu gest | Long Press (implicit) | OnLongClickListener |
| Drag preview | UIDragItem.previewProvider | DragShadowBuilder |
| Feedback tactil | UIImpactFeedbackGenerator | HapticFeedbackConstants.LONG_PRESS |
| Animația de revenire | UIDragPreviewTarget | ViewPropertyAnimator |
| Drop proposal | UIDropProposal (.move/.copy) | ACTION_DROP + flag-uri |
| DnD între aplicații | iOS 11+ Split View (iPad) | Android 7.0+ Split Screen |
Accesibilitate: utilizatorii cu limitări motorii pot să nu poată executa gestul de tragere. Oferiți alternative prin butoane „Mută sus/jos” pentru liste, meniu contextual „Mută în folder” pentru fișiere. iOS VoiceOver suportă acțiunea rotor „Drag” pentru mutarea elementelor. Android TalkBack oferă acțiuni personalizate prin AccessibilityNodeInfo.addAction(). Nike Run Club și Apple Health folosesc DnD pentru reordonarea metricilor pe dashboard — cu acces prin butoane standard.
Întrebări frecvente
Gestul standard pentru începerea Drag-and-Drop este Long Press (apăsare lungă) cu durata de 300–500 ms. iOS folosește mecanismul încorporat UIDragInteraction, care convertește automat atingerea prelungită în capturare. Android necesită apelarea explicită a startDragAndDrop() în callback-ul OnLongClickListener. În unele cazuri (de exemplu, în jocuri), DnD poate începe cu o simplă atingere fără întârziere.
Da, Drag-and-Drop inter-aplicații este suportat în iOS 11+ (iPad) și Android 7.0+. Pe iPad, tragerea funcționează în modul Split View și Slide Over — utilizatorul poate lua text din Safari și îl poate muta în Note. în Android, DnD între aplicații funcționează în Split Screen. Datele sunt transmise prin UIPasteConfiguration (iOS) sau ClipData (Android) cu specificarea tipurilor suportate (UTI, MIME).
Conflictul DnD și Scroll se rezolvă prin întârzierea capturării. Dacă utilizatorul începe mișcarea degetului înainte de expirarea timeout-ului Long Press (500 ms), gestul este interpretat ca derulare, nu ca Drag-and-Drop. În iOS, UIDragInteraction gestionează automat acest conflict prin cancelsTouchesInView. În Android, ItemTouchHelper folosește un prag — dacă mișcarea depășește pragul TouchSlop, Long Press este anulat în favoarea derulării.
Drag-and-Drop suportă orice tip de date: text, imagini, fișiere, URL, obiecte personalizate. iOS folosește NSItemProvider cu tipuri UTI (public.text, public.image, public.file-url). Android — ClipData cu tipuri MIME (text/plain, image/png, application/octet-stream). Pentru date personalizate se creează ClipData.Item cu Intent. La DnD inter-aplicații, datele sunt ambalate în formate universale: plain text, HTML, RTF, UIImage/PNG.
În iOS, animația de revenire este gestionată prin UIDragPreviewTarget — poziția finală la care preview revine animat. În Android, folosiți ViewPropertyAnimator cu translateX/translateY pentru a returna elementul la poziția originală. Durata animației — 200–300 ms cu curbă easing (EaseOut). UIKit adaugă automat UIDragPreview cu efect de paralaxă, care revine lin la anularea gestului.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și