Arrastrar un elemento de la UI
Cómo implementar un elemento de la UI arrastrable.
Arrastrar y soltar (drag and drop) es una interacción común en apps móviles. A medida que el usuario realiza una pulsación larga (a veces llamada touch & hold) en un widget, aparece otro widget debajo del dedo del usuario, y el usuario arrastra el widget a una ubicación final y lo suelta. En esta receta, construirás una interacción de arrastrar y soltar donde el usuario realiza una pulsación larga sobre una opción de comida, y luego arrastra esa comida a la foto del cliente que la está pagando.
La siguiente animación muestra el comportamiento de la app:
Esta receta comienza con una lista preconstruida de elementos del menú y una fila de clientes. El primer paso es reconocer una pulsación larga y mostrar una foto arrastrable de un elemento del menú.
Presionar y arrastrar
#Flutter proporciona un widget llamado LongPressDraggable
que proporciona exactamente el comportamiento que necesitas para comenzar
una interacción de arrastrar y soltar. Un widget LongPressDraggable
reconoce cuándo ocurre una pulsación larga y luego
muestra un nuevo widget cerca del dedo del usuario.
A medida que el usuario arrastra, el widget sigue el dedo del usuario.
LongPressDraggable te da control total sobre el
widget que el usuario arrastra.
Cada elemento de la lista de menú se muestra con un widget personalizado
MenuListItem.
MenuListItem(
name: item.name,
price: item.formattedTotalItemPrice,
photoProvider: item.imageProvider,
)
Envuelve el widget MenuListItem con un widget LongPressDraggable.
LongPressDraggable<Item>(
data: item,
dragAnchorStrategy: pointerDragAnchorStrategy,
feedback: DraggingListItem(
dragKey: _draggableKey,
photoProvider: item.imageProvider,
),
child: MenuListItem(
name: item.name,
price: item.formattedTotalItemPrice,
photoProvider: item.imageProvider,
),
);
En este caso, cuando el usuario realiza una pulsación larga en el
widget MenuListItem, el widget LongPressDraggable
muestra un DraggingListItem.
Este DraggingListItem muestra una foto del
elemento de comida seleccionado, centrado debajo
del dedo del usuario.
La propiedad dragAnchorStrategy se establece en
pointerDragAnchorStrategy.
El valor de esta propiedad le indica a LongPressDraggable
que base la posición de DraggableListItem en el
dedo del usuario. A medida que el usuario mueve un dedo,
el DraggableListItem se mueve con él.
Arrastrar y soltar es de poca utilidad si no se transmite información
cuando se suelta el elemento.
Por esta razón, LongPressDraggable toma un parámetro data.
En este caso, el tipo de data es Item,
que contiene información sobre el
elemento de menú de comida sobre el que presionó el usuario.
Los datos (data) asociados con un LongPressDraggable
se envían a un widget especial llamado DragTarget,
donde el usuario suelta el gesto de arrastre.
Implementarás el comportamiento de soltar a continuación.
Soltar el elemento arrastrable
#El usuario puede soltar un LongPressDraggable donde prefiera,
pero soltarlo no tiene ningún efecto a menos que se suelte
encima de un DragTarget. Cuando el usuario suelta un elemento arrastrable encima de
un widget DragTarget, el widget DragTarget
puede aceptar o rechazar los datos del elemento arrastrable.
En esta receta, el usuario debe soltar un elemento del menú en un
widget CustomerCart para añadir el elemento del menú al carrito del usuario.
CustomerCart(
hasItems: customer.items.isNotEmpty,
highlighted: candidateItems.isNotEmpty,
customer: customer,
);
Envuelve el widget CustomerCart con un widget DragTarget.
DragTarget<Item>(
builder: (context, candidateItems, rejectedItems) {
return CustomerCart(
hasItems: customer.items.isNotEmpty,
highlighted: candidateItems.isNotEmpty,
customer: customer,
);
},
onAcceptWithDetails: (details) {
_itemDroppedOnCustomerCart(item: details.data, customer: customer);
},
)
El DragTarget muestra tu widget existente y
también se coordina con LongPressDraggable para reconocer
cuándo el usuario arrastra un elemento arrastrable encima del DragTarget.
El DragTarget también reconoce cuándo el usuario suelta
un elemento arrastrable encima del widget DragTarget.
Cuando el usuario arrastra un elemento arrastrable sobre el widget DragTarget,
candidateItems contiene los elementos de datos que el usuario está arrastrando.
Esto te permite cambiar la apariencia de tu widget
cuando el usuario está arrastrando sobre él. En este caso,
el widget Customer se vuelve rojo cuando se arrastran elementos por encima del
widget DragTarget. La apariencia visual roja se configura con la
propiedad highlighted dentro del widget CustomerCart.
Cuando el usuario suelta un elemento arrastrable sobre el widget DragTarget,
se invoca el callback onAcceptWithDetails. Es en este momento cuando puedes
decidir si aceptas o no los datos que se soltaron.
En este caso, el elemento siempre se acepta y se procesa.
Podrías elegir inspeccionar el elemento entrante para tomar una
decisión diferente.
Ten en cuenta que el tipo de elemento que se suelta en DragTarget
debe coincidir con el tipo del elemento arrastrado desde LongPressDraggable.
Si los tipos no son compatibles, entonces
el método onAcceptWithDetails no se invoca.
Con un widget DragTarget configurado para aceptar los
datos deseados, ahora puedes transmitir datos de una parte
de tu UI a otra arrastrando y soltando.
En el siguiente paso, actualizarás el carrito del cliente con el elemento de menú que se soltó.
Añadir un elemento del menú a un carrito
#Cada cliente está representado por un objeto Customer,
que mantiene un carrito de elementos y un precio total.
class Customer {
Customer({required this.name, required this.imageProvider, List<Item>? items})
: items = items ?? [];
final String name;
final ImageProvider imageProvider;
final List<Item> items;
String get formattedTotalItemPrice {
final totalPriceCents = items.fold<int>(
0,
(prev, item) => prev + item.totalPriceCents,
);
return '\$${(totalPriceCents / 100.0).toStringAsFixed(2)}';
}
}
El widget CustomerCart muestra la foto del cliente,
el nombre, el total y la cantidad de elementos basándose en una instancia de Customer.
Para actualizar el carrito de un cliente cuando se suelta un elemento de menú,
añade el elemento soltado al objeto Customer asociado.
void _itemDroppedOnCustomerCart({
required Item item,
required Customer customer,
}) {
setState(() {
customer.items.add(item);
});
}
El método _itemDroppedOnCustomerCart se invoca en
onAcceptWithDetails() cuando el usuario suelta un elemento de menú en un
widget CustomerCart. Al añadir el elemento soltado al
objeto customer, e invocar setState() para provocar una
actualización del diseño, la UI se refresca con el total de
precio y cantidad de elementos del nuevo cliente.
¡Felicitaciones! Tienes una interacción de arrastrar y soltar que añade elementos de comida al carrito de compras de un cliente.
Ejemplo interactivo
#Ejecutar la app:
- Desplazarse por los elementos de comida.
- Mantén presionado uno con tu dedo o haz clic y mantén presionado con el ratón.
- Mientras lo sostienes, la imagen del elemento de comida aparecerá encima de la lista.
- Arrastra la imagen y suéltala sobre una de las personas en la parte inferior de la pantalla. El texto debajo de la imagen se actualiza para reflejar el cobro para esa persona. Puedes continuar agregando elementos de comida y ver cómo se acumulan los cobros.
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-05. Ver código fuente oreportar un problema.