Drag-and-Drop — un gesto interactivo para arrastrar un objeto visual por la pantalla con el dedo. El gesto consta de tres fases: agarre (long press o toque), movimiento (desplazar el dedo con el objeto) y soltar (dejar caer en la zona objetivo). Se utiliza para reordenar elementos, mover archivos entre carpetas y organizar interfaces (drag to reorder, drag to resize). En iOS se implementa mediante UIDragInteraction, en Android — mediante DragEvent y startDragAndDrop.
Puntos clave
Drag-and-Drop (DnD) es un método de manipulación de elementos gráficos de la interfaz donde el usuario agarra un objeto con el dedo o el ratón, lo mueve a otra posición y lo suelta. En las interfaces móviles, Drag-and-Drop generalmente se inicia con una pulsación larga — el usuario mantiene presionado el elemento durante 300–500 ms, después de lo cual el sistema cambia la interfaz al modo de arrastre y el movimiento del dedo desplaza el objeto.
Históricamente, Drag-and-Drop se originó en las interfaces de escritorio (Xerox Star, 1981; Macintosh, 1984) como una alternativa a los comandos copiar/pegar. En las plataformas móviles, el soporte completo apareció en iOS 11 (2017) con UIDragInteraction y en Android 7.0 (2016) con Multi-Window Drag-and-Drop. Antes de eso, el arrastre en aplicaciones móviles se implementaba mediante soluciones personalizadas con reconocedores de gestos.
Conceptos clave: drag session (sesión de arrastre), drag items (elementos arrastrables), drag preview (representación visual del objeto), drop target (zona de destino), drop proposal (acción al soltar: mover, copiar, enlazar). El sistema gestiona la sesión a nivel del sistema operativo, lo que permite arrastrar objetos entre diferentes aplicaciones (por ejemplo, una foto de Galería a Notas).
Drag-and-Drop se divide en tres fases secuenciales. Fase 1 — Agarre (Drag Start): el usuario inicia el gesto (generalmente Long Press), el sistema crea una sesión de arrastre, captura los datos del objeto y muestra una vista previa de arrastre — una copia semitransparente del elemento que sigue al dedo. En esta fase, el sistema rechaza otros gestos (desplazamiento, selección de texto) hasta que se complete el DnD.
Fase 2 — Movimiento (Drag Move): el dedo se mueve por la pantalla, la vista previa sigue el punto de contacto. El sistema determina continuamente el destino bajo el dedo y envía eventos de drag-enter, drag-move y drag-exit. El destino puede reaccionar visualmente: resaltarse, expandirse o mostrar una línea de inserción. Esta fase dura de 0.5 a 10+ segundos según la complejidad de la tarea.
Fase 3 — Soltar (Drop): el dedo se levanta de la pantalla. El sistema finaliza la sesión de arrastre y llama al callback de destino. Si el destino rechaza la colocación (por ejemplo, arrastrar un archivo a una carpeta sin permisos de escritura), la vista previa vuelve animadamente a la posición original (cancel animation). Si se acepta, el elemento desaparece de la posición original y aparece en el destino.
| Fase | Evento iOS | Evento Android | Estado visual |
|---|---|---|---|
| Agarre | UIDragInteractionDelegate.dragSessionWillBegin | View.OnLongClickListener → startDragAndDrop | Aparece la vista previa bajo el dedo |
| Movimiento | UIDropInteractionDelegate.dragSessionDidUpdate | View.OnDragListener.onDrag (ACTION_DRAG_MOVED) | La vista previa se mueve, el destino se resalta |
| Soltar | UIDropInteractionDelegate.performDrop | View.OnDragListener.onDrag (ACTION_DROP) | Animación de colocación o retorno |
Arrastre entre aplicaciones es una función disponible en ambas plataformas. iOS admite Drag-and-Drop entre aplicaciones en modo Split View y Slide Over (iPad). Android admite el arrastre entre aplicaciones en modo Split Screen. Los datos se transfieren mediante UIPasteConfiguration (iOS) o ClipData (Android). El desarrollador especifica los tipos de datos compatibles (UTI para iOS, MIME para Android).
UIDragInteraction es la API principal de iOS para arrastrar, añadida en iOS 11. Para habilitar el arrastre desde una View, agregue UIDragInteraction con UIDragInteractionDelegate. El delegado define qué elementos se pueden arrastrar, su apariencia y comportamiento. Para recibir elementos, use UIDropInteraction con UIDropInteractionDelegate, que determina si la View puede aceptar una colocación y cómo procesar los datos.
// UIDragInteraction — arrastrar un elemento de una colección
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 — una copia reducida del elemento
dragItem.previewProvider = {
let previewView = UIImageView(image: thumbnailImage)
previewView.alpha = 0.8
return UIDragPreview(view: previewView)
}
return [dragItem]
}
}UIDropInteractionDelegate es la interfaz espejo para recibir colocaciones. El método canHandle(_:) verifica si el tipo de datos es compatible. sessionDidUpdate(_:) actualiza visualmente el estado (resaltado, línea de inserción). performDrop(_:) realiza el procesamiento final de datos. iOS llama automáticamente a UIDropProposal con el tipo de operación: .move, .copy o .forbidden. El tipo de operación afecta la visualización (un icono + en la esquina de la vista previa para copiar, un signo de prohibición para forbidden).
View.startDragAndDrop() es el método de Android SDK para iniciar un arrastre, disponible desde API 24 (Android 7.0). Se llama tras agarrar el elemento (generalmente en onLongClick). Parámetros: ClipData (datos), DragShadowBuilder (sombra visual), Object myLocalState (estado local), flags. DragShadowBuilder crea un Bitmap que sigue al dedo. El sistema gestiona automáticamente las animaciones y los eventos táctiles durante el arrastre.
// Drag-and-Drop de un elemento RecyclerView con reordenación
class ReorderAdapter(private val items: MutableList<String>) :
RecyclerView.Adapter<ReorderAdapter.ViewHolder>() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.setOnLongClickListener {
// Creando ClipData para la transferencia de datos
val clipData = ClipData.newPlainText("item", items[position])
// DragShadowBuilder personalizado con vista previa reducida
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
}
}
}Recepción de colocación en Android se implementa mediante View.setOnDragListener(). El listener recibe eventos ACTION_DRAG_STARTED, ACTION_DRAG_ENTERED, ACTION_DRAG_LOCATION, ACTION_DRAG_EXITED, ACTION_DROP y ACTION_DRAG_ENDED. En el evento ACTION_DROP, los datos se extraen de ClipData y se realiza la acción objetivo. Para RecyclerView con reordenación, se recomienda ItemTouchHelper.SimpleCallback — un mecanismo integrado que maneja automáticamente Long Press para agarrar, animación de movimiento y los métodos utilitarios onMove/onSwiped.
Reordenación de listas (drag to reorder) es el escenario DnD más común: los usuarios arrastran elementos de la lista para cambiar su orden. Ejemplos: reorganizar contactos en favoritos, ordenar tareas en trackers (Trello, Todoist), reordenar pistas en una lista de reproducción (Spotify, Apple Music). Se implementa mediante ItemTouchHelper en Android o UILongPressGestureRecognizer con reordenación de celdas en iOS.
Gestores de archivos — Drag-and-Drop para copiar y mover archivos entre carpetas. iOS Files App, Android Files by Google, Dropbox — todos admiten DnD. Arrastrar un archivo a una carpeta lo mueve hacia adentro (move), arrastrar con Option/Ctrl presionado lo copia (copy). El destino se resalta visualmente al pasar el cursor, mostrando los límites de la carpeta.
Tableros Kanban — Trello, Jira, Notion usan Drag-and-Drop para mover tarjetas entre columnas (To Do → In Progress → Done). Al arrastrar, la tarjeta se desprende de su columna de origen, sigue al dedo y al cruzar el límite de otra columna se inserta con animación. iOS 11+ admite UIDragPreview con efecto parallax, donde la vista previa se inclina ligeramente del punto de contacto, creando profundidad.
Secciones Springboard (iOS) — arrastre de iconos de aplicaciones en la pantalla de inicio de iOS. Una pulsación larga en un icono activa el modo “temblor” (los iconos se mueven), después de lo cual el usuario puede mover iconos entre páginas y crear carpetas. Este es uno de los patrones UX de DnD más complejos, ya que requiere manejar simultáneamente el arrastre, la animación de temblor y la agrupación en carpetas.
Retroalimentación visual es críticamente importante para Drag-and-Drop. El objeto arrastrado debe cambiar: encogerse (iOS: escala 0.8–0.9), volverse semitransparente (alpha 0.7–0.8) y elevarse sobre la interfaz con una sombra (shadow offset). El destino debe reaccionar visualmente al pasar el cursor: resaltarse, expandirse o mostrar un borde. Sin estas señales, el usuario no puede saber dónde puede soltar el objeto.
Animación de retorno (drag cancel) — si el usuario suelta el elemento fuera de la zona de colocación o sobre una zona no válida, el objeto debe volver animadamente a su posición original. iOS UIDragInteractionDelegate proporciona dragInteraction(_:sessionDidMove:) para seguimiento y dragInteraction(_:session:willEndWith:) para animación de retorno. Android View.setOnDragListener recibe ACTION_DRAG_ENDED, donde se puede iniciar una animación de retorno mediante ValueAnimator u ObjectAnimator.
| Recomendación | iOS | Android |
|---|---|---|
| Agarre por gesto | Long Press (predeterminado) | OnLongClickListener |
| Vista previa de arrastre | UIDragItem.previewProvider | DragShadowBuilder |
| Retroalimentación háptica | UIImpactFeedbackGenerator | HapticFeedbackConstants.LONG_PRESS |
| Animación de retorno | UIDragPreviewTarget | ViewPropertyAnimator |
| Propuesta de colocación | UIDropProposal (.move/.copy) | ACTION_DROP + flags |
| DnD entre aplicaciones | iOS 11+ Split View (iPad) | Android 7.0+ Split Screen |
Accesibilidad: los usuarios con limitaciones motoras pueden no poder realizar el gesto de arrastre. Proporcione alternativas mediante botones “Mover arriba/abajo” para listas y un menú contextual “Mover a carpeta” para archivos. iOS VoiceOver admite la acción de rotor “Arrastrar” para mover elementos. Android TalkBack proporciona acciones personalizadas mediante AccessibilityNodeInfo.addAction(). Nike Run Club y Apple Health usan DnD para reordenar métricas en el panel — con acceso mediante botones estándar.
Preguntas frecuentes
El gesto estándar para iniciar Drag-and-Drop es una pulsación larga de 300–500 ms. iOS utiliza el mecanismo integrado UIDragInteraction que convierte automáticamente un toque sostenido en un agarre. Android requiere una llamada explícita a startDragAndDrop() en el callback OnLongClickListener. En algunos casos (por ejemplo, juegos), DnD puede comenzar con un toque simple sin demora.
Sí, Drag-and-Drop entre aplicaciones es compatible con iOS 11+ (iPad) y Android 7.0+. En iPad, el arrastre funciona en modo Split View y Slide Over — el usuario puede tomar texto de Safari y soltarlo en Notas. En Android, DnD entre aplicaciones funciona en Split Screen. Los datos se transfieren mediante UIPasteConfiguration (iOS) o ClipData (Android) con tipos compatibles especificados (UTI, MIME).
El conflicto DnD y Scroll se resuelve mediante un retardo de agarre. Si el usuario comienza a mover el dedo antes de que expire el tiempo de espera de Long Press (500 ms), el gesto se interpreta como desplazamiento en lugar de Drag-and-Drop. En iOS, UIDragInteraction maneja automáticamente este conflicto mediante cancelsTouchesInView. En Android, ItemTouchHelper utiliza un umbral — si el movimiento supera el límite de TouchSlop, Long Press se cancela a favor del desplazamiento.
Drag-and-Drop admite cualquier tipo de dato: texto, imágenes, archivos, URLs, objetos personalizados. iOS usa NSItemProvider con tipos UTI (public.text, public.image, public.file-url). Android usa ClipData con tipos MIME (text/plain, image/png, application/octet-stream). Para datos personalizados, se crea un ClipData.Item con Intent. Para DnD entre aplicaciones, los datos se empaquetan en formatos universales: texto plano, HTML, RTF, UIImage/PNG.
En iOS, la animación de retorno se maneja mediante UIDragPreviewTarget — la posición final a la que la vista previa regresa animadamente. En Android, use ViewPropertyAnimator con translateX/translateY para devolver el elemento a su posición original. La duración de la animación es de 200–300 ms con una curva de easing (EaseOut). UIKit agrega automáticamente un UIDragPreview con efecto parallax que regresa suavemente cuando se cancela el gesto.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también