Drag-and-Drop — интерактивни гест превлачења визуелног објекта по екрану помоћу прста. Гест се састоји из три фазе: хватање (long press или додир), помијерање (покрет прста са објектом) и отпуштање (бацање у циљну зону). Користи се за промену редоследа елемената, премештање датотека између фолдера, организацију интерфејса (drag to reorder, drag to resize). На iOS-у се имплементира кроз UIDragInteraction, на Android-у — кроз DragEvent и startDragAndDrop.
Главно
Drag-and-Drop (DnD, превлачење) — метода манипулације графичким елементима интерфејса у којој корисник хвата објекат прстом или мишем, премешта га на другу позицију и отпушта. У мобилним интерфејсима, Drag-and-Drop се обично покреће дугим притиском (Long Press) — корисник држи елеменат 300–500 мс, након чега систем пребацује интерфејс у режим превлачења, а покрет прста помера објекат за собом.
Историјски, Drag-and-Drop се појавио у десктоп интерфејсима (Xerox Star, 1981; Macintosh, 1984) као алтернатива командама копирај/лепи. На мобилним платформама, пуна подршка се појавила у iOS 11 (2017) са UIDragInteraction и у Android 7.0 (2016) са Multi-Window Drag-and-Drop. Пре тога, превлачење у мобилним апликацијама је имплементирано кроз прилагођена решења путем gesture recognizers.
Кључни концепти: drag session (сесија превлачења), drag items (превучени објекти), drag preview (визуелни приказ објекта), drop target (зона испуста), drop proposal (радња при испусту: премести, копирај, повежи). Систем управља сесијом на нивоу оперативног система, што омогућава превлачење објеката између различитих апликација (нпр. фотографија из Галерије у Белешке).
Drag-and-Drop се дели на три узастопне фазе. Фаза 1 — хватање (Drag Start): корисник покреће гест (обично Long Press), систем креира сесију превлачења, преузима податке објекта и приказује drag preview — полупрозирну копију елемента која прати прст. У овој фази, систем одбацује друге гестове (скроловање, селекција текста) до завршетка DnD.
Фаза 2 — помијерање (Drag Move): прст се креће по екрану, drag preview прати тачку додира. Систем непрекидно одређује drop target испод прста и шаље догађаје drag enter, drag move и drag exit. Drop target може визуелно да реагује: да се упали, прошири или прикаже линију уметања. Ова фаза траје од 0.5 до 10+ секунди у зависности од сложености задатка.
Фаза 3 — отпуштање (Drop): прст се подиже са екрана. Систем завршава сесију превлачења и позива drop callback код циљног елемента. Ако drop target одбија испуст (нпр. превлачење датотеке у фолдер без права писања), drag preview се анимирано враћа на првобитну позицију (cancel animation). Ако је испуст прихваћен, елеменат нестаје са првобитне позиције и појављује се на циљној.
| Фаза | iOS догађај | Android догађај | Визуелно стање |
|---|---|---|---|
| Хватање | UIDragInteractionDelegate.dragSessionWillBegin | View.OnLongClickListener → startDragAndDrop | Drag preview се појављује испод прста |
| Помијерање | UIDropInteractionDelegate.dragSessionDidUpdate | View.OnDragListener.onDrag (ACTION_DRAG_MOVED) | Preview се креће, target упаљен |
| Отпуштање | UIDropInteractionDelegate.performDrop | View.OnDragListener.onDrag (ACTION_DROP) | Анимација испуста или повратка |
Превлачење између апликација — функција доступна на обе платформе. iOS подржава Drag-and-Drop између апликација у режиму Split View и Slide Over (iPad). Android подржава превлачење између апликација у режиму Split Screen. Подаци се преносе путем UIPasteConfiguration (iOS) или ClipData (Android). Програмер наводи подржане типове података (UTI за iOS, MIME за Android).
UIDragInteraction — главни iOS API за превлачење, додат у iOS 11. За омогућавање превлачења из View-а, додајте UIDragInteraction са UIDragInteractionDelegate. Делегат одређује који се елементи превлаче, њихов изглед и понашање. За пријем елемената користи се UIDropInteraction са UIDropInteractionDelegate, који одређује да ли View може да прихвати испуст и како да обради податке.
// UIDragInteraction — превлачење елемента из колекције
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 — умањена копија елемента
dragItem.previewProvider = {
let previewView = UIImageView(image: thumbnailImage)
previewView.alpha = 0.8
return UIDragPreview(view: previewView)
}
return [dragItem]
}
}UIDropInteractionDelegate — огледалски интерфејс за пријем испуста. Метода canHandle(_:) проверава да ли је тип података подржан. sessionDidUpdate(_:) визуелно ажурира стање (паљење, линија уметања). performDrop(_:) врши коначну обраду података. iOS аутоматски позива UIDropProposal са типом операције: .move (премести), .copy (копирај), .forbidden (забрањено). Тип операције утиче на визуелно приказивање (иконица + у углу preview за копирање, знак забране за forbidden).
View.startDragAndDrop() — Android SDK метода за почетак превлачења, доступна од API 24 (Android 7.0). Позива се након хватања елемента (обично у onLongClick). Параметри: ClipData (подаци), DragShadowBuilder (визуелна сенка), Object myLocalState (локално стање), flags. DragShadowBuilder креира Bitmap који прати прст. Систем аутоматски управља анимацијом и догађајима додира током превлачења.
// Drag-and-Drop RecyclerView елемента са преуређивањем
class ReorderAdapter(private val items: MutableList<String>) :
RecyclerView.Adapter<ReorderAdapter.ViewHolder>() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.setOnLongClickListener {
// Креирамо ClipData за пренос података
val clipData = ClipData.newPlainText("item", items[position])
// Прилагођени DragShadowBuilder са умањеним preview
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
}
}
}Пријем испуста у Android-у се реализује кроз View.setOnDragListener(). Ослушкивач прима догађаје ACTION_DRAG_STARTED, ACTION_DRAG_ENTERED, ACTION_DRAG_LOCATION, ACTION_DRAG_EXITED, ACTION_DROP, ACTION_DRAG_ENDED. У догађају ACTION_DROP, подаци се извлаче из ClipData и извршава се циљна акција. За RecyclerView са преуређивањем препоручује се ItemTouchHelper.SimpleCallback — уграђени механизам који аутоматски обрађује Long Press за хватање, анимацију помијерања елемената и помоћне методе onMove/onSwiped.
Преуређивање листи (drag to reorder) — најчешћи DnD сценаријо: корисник превлачи елементе листе да би променио њихов редослед. Примери: премештање контаката у омиљенима, сортирање задатака у тракерима (Trello, Todoist), промена редоследа песама у плејлисти (Spotify, Apple Music). Реализује се кроз ItemTouchHelper у Android-у или UILongPressGestureRecognizer + премештање ћелија у iOS-у.
Менаџери датотека — Drag-and-Drop за копирање и премештање датотека између фолдера. iOS Files App, Android Files by Google, Dropbox — сви подржавају DnD. Превлачење датотеке на фолдер је премешта унутар (move), превлачење са притиснутим типком Option/Ctrl је копира (copy). Drop target се визуелно пали при налажењу, показујући границе фолдера.
Kanban табле — Trello, Jira, Notion користе Drag-and-Drop за премештање картица између колона (To Do → In Progress → Done). Током превлачења, картица се одваја од изворне колоне, прати прст, и по преласку границе друге колоне умеће се са анимацијом. iOS 11+ подржава UIDragPreview са ефектом паралаксе, где се preview благо одмиче од тачке додира, стварајући дубину.
Springboard секције (iOS) — превлачење иконица апликација на почетном екрану iOS. Дуги притисак на иконицу активира режим „jiggling” (иконице се тресу), након чега корисник може да премешта иконице између страница и креира фолдере. Ово је један од најсложенијих UX DnD образаца, јер захтева истовремено управљање превлачењем, анимацијом тресења и груписањем у фолдере.
Визуелна повратна спрега — критична за Drag-and-Drop. Превучени објекат треба да се промијени: смањи (у iOS: scale 0.8–0.9), постане полупрозиран (alpha 0.7–0.8) и подигне се изнад интерфејса са сенком (shadow offset). Drop target треба визуелно да реагује на налажење: да се упали (highlight), прошири (expand) или покаже ивице (border). Без ових сигнала, корисник не разуме куда може да отпусти објекат.
Анимација повратка (drag cancel) — ако корисник отпусти елеменат ван зоне испуста или изнад неважеће зоне, објекат треба анимирано да се врати на првобитну позицију. iOS UIDragInteractionDelegate пружа dragInteraction(_:sessionDidMove:) за праћење и dragInteraction(_:session:willEndWith:) за анимацију повратка. Android View.setOnDragListener прима ACTION_DRAG_ENDED, где се може покренути анимација повратка путем ValueAnimator или ObjectAnimator.
| Препорука | iOS | Android |
|---|---|---|
| Хватање гестом | Long Press (подразумевано) | OnLongClickListener |
| Drag preview | UIDragItem.previewProvider | DragShadowBuilder |
| Тактилна повратна спрега | UIImpactFeedbackGenerator | HapticFeedbackConstants.LONG_PRESS |
| Анимација повратка | UIDragPreviewTarget | ViewPropertyAnimator |
| Drop proposal | UIDropProposal (.move/.copy) | ACTION_DROP + заставице |
| Међуапликацијско DnD | iOS 11+ Split View (iPad) | Android 7.0+ Split Screen |
Приступачност: корисници са моторним ограничењима можда не ће моћи да изврше гест превлачења. Омогућите алтернативе кроз дугмад „Помери горе/доле” за листе, контекстни мени „Премести у фолдер” за датотеке. iOS VoiceOver подржава ротор акцију „Drag” за премештање елемената. Android TalkBack пружа прилагођене акције кроз AccessibilityNodeInfo.addAction(). Nike Run Club и Apple Health користе DnD за преуређивање метрика на контролној табли — са приступом кроз стандардне дугмаде.
Често постављана питања
Стандардни гест за почетак Drag-and-Drop је Long Press (дуги притисак) у трајању 300–500 мс. iOS користи уграђени UIDragInteraction механизам који аутоматски претвара дуго додиривање у хватање. Android захтева јасан позив startDragAndDrop() у OnLongClickListener повратној колини. У неким случајевима (нпр. у играма), DnD може да почне обичним додиром без кашњења.
Да, међуапликацијски Drag-and-Drop је подржан на iOS 11+ (iPad) и Android 7.0+. На iPad-у, превлачење ради у режиму Split View и Slide Over — корисник може да узме текст из Safari-а и премести га у Белешке. У Android-у, DnD између апликација ради у Split Screen-у. Подаци се преносе путем UIPasteConfiguration (iOS) или ClipData (Android) са наводом подржаних типова (UTI, MIME).
Конфликт DnD и Scroll се решава кашњењем хватања. Ако корисник почне да помиче прст пре истека Long Press тајмаута (500 мс), гест се тумачи као скроловање, а не као Drag-and-Drop. У iOS-у, UIDragInteraction аутоматски управља овим конфликтом кроз cancelsTouchesInView. У Android-у, ItemTouchHelper користи праг — ако покрет премаши TouchSlop праг, Long Press се отказује у корист скроловања.
Drag-and-Drop подржава све типове података: текст, слике, датотеке, URL, прилагођене објекте. iOS користи NSItemProvider са UTI типовима (public.text, public.image, public.file-url). Android — ClipData са MIME типовима (text/plain, image/png, application/octet-stream). За прилагођене податке креира се ClipData.Item са Intent-ом. При међуапликацијском DnD, подаци се пакују у универзалне формате: plain text, HTML, RTF, UIImage/PNG.
У iOS-у, анимација повратка се управља кроз UIDragPreviewTarget — коначна позиција којој се preview анимирано враћа. У Android-у, користите ViewPropertyAnimator са translateX/translateY за враћање елемента на првобитну позицију. Време анимације — 200–300 мс са easing кривуљом (EaseOut). UIKit аутоматски додаје UIDragPreview са ефектом паралаксе, који се глатко враћа при отказивању геста.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође