Saltar al contenido principal

Toques, arrastres y otros gestos

Cómo funcionan los gestos, como toques y arrastres, en Flutter.

Este documento explica cómo escuchar y responder a gestos en Flutter. Los ejemplos de gestos incluyen toques, arrastres y escalado.

El sistema de gestos en Flutter tiene dos capas separadas. La primera capa tiene eventos de puntero sin procesar que describen la ubicación y el movimiento de los punteros (por ejemplo, toques táctiles, mouses y lápices ópticos) a través de la pantalla. La segunda capa tiene gestos que describen acciones semánticas que consisten en uno o más movimientos de puntero.

Punteros (Pointers)

#

Los punteros representan datos sin procesar sobre la interacción del usuario con la pantalla del dispositivo. Hay cuatro tipos de eventos de puntero:

PointerDownEvent

El puntero ha entrado en contacto con la pantalla en una ubicación en particular.

PointerMoveEvent

El puntero se ha movido de una ubicación en la pantalla a otra.

PointerUpEvent

El puntero ha dejado de estar en contacto con la pantalla.

PointerCancelEvent

La entrada de este puntero ya no está dirigida a esta app.

Al presionar el puntero, el framework realiza una prueba de impacto (hit test) en tu app para determinar qué widget existe en la ubicación donde el puntero contactó la pantalla. El evento de presión del puntero (y los eventos subsecuentes para ese puntero) se despachan luego al widget más interno encontrado por la prueba de impacto. A partir de ahí, los eventos se propagan hacia arriba en el árbol y se despachan a todos los widgets en el camino desde el widget más interno hasta la raíz del árbol. No existe un mecanismo para cancelar o detener la propagación posterior de los eventos de puntero.

Para escuchar eventos de puntero directamente desde la capa de widgets, usa un widget Listener. Sin embargo, por lo general, considera usar gestos (como se analiza a continuación) en su lugar.

Gestos

#

Los gestos representan acciones semánticas (por ejemplo, toque, arrastre y escala) que se reconocen a partir de múltiples eventos de puntero individuales, potencialmente incluso de múltiples punteros individuales. Los gestos pueden despachar múltiples eventos, correspondientes al ciclo de vida del gesto (por ejemplo, inicio del arrastre, actualización del arrastre y fin del arrastre):

Tap

onTapDown

Un puntero que podría causar un toque ha contactado la pantalla en una ubicación particular.

onTapUp

Un puntero que desencadena un toque ha dejado de contactar la pantalla en una ubicación particular.

onTap

El puntero que anteriormente desencadenó el onTapDown también desencadenó onTapUp, lo que termina causando un toque.

onTapCancel

El puntero que anteriormente desencadenó el onTapDown no terminará causando un toque.

Double tap

onDoubleTap

El usuario ha tocado la pantalla en la misma ubicación dos veces en rápida sucesión.

Long press

onLongPress

Un puntero ha permanecido en contacto con la pantalla en la misma ubicación durante un largo período de tiempo.

Vertical drag

onVerticalDragStart

Un puntero ha contactado la pantalla y podría comenzar a moverse verticalmente.

onVerticalDragUpdate

Un puntero que está en contacto con la pantalla y moviéndose verticalmente se ha movido en la dirección vertical.

onVerticalDragEnd

Un puntero que estaba previamente en contacto con la pantalla y moviéndose verticalmente ya no está en contacto con la pantalla y se movía a una velocidad específica cuando dejó de contactar la pantalla.

Horizontal drag

onHorizontalDragStart

Un puntero ha contactado la pantalla y podría comenzar a moverse horizontalmente.

onHorizontalDragUpdate

Un puntero que está en contacto con la pantalla y moviéndose horizontalmente se ha movido en la dirección horizontal.

onHorizontalDragEnd

Un puntero que estaba previamente en contacto con la pantalla y moviéndose horizontalmente ya no está en contacto con la pantalla y se estaba moviendo a una velocidad específica cuando dejó de hacer contacto con la pantalla.

Pan

onPanStart

Un puntero ha contactado la pantalla y podría comenzar a moverse horizontal o verticalmente. Este callback falla si onHorizontalDragStart o onVerticalDragStart está configurado.

onPanUpdate

Un puntero que está en contacto con la pantalla y se está moviendo en la dirección vertical u horizontal. Este callback falla si onHorizontalDragUpdate o onVerticalDragUpdate está configurado.

onPanEnd

Un puntero que estaba previamente en contacto con la pantalla ya no está en contacto con la pantalla y se está moviendo a una velocidad específica cuando dejó de contactar la pantalla. Este callback falla si onHorizontalDragEnd o onVerticalDragEnd está configurado.

Agregar detección de gestos a los widgets

#

Para escuchar gestos desde la capa de widgets, usa un GestureDetector.

Si estás utilizando Material Components, muchos de esos widgets ya responden a toques o gestos. Por ejemplo, IconButton y TextButton responden a pulsaciones (toques), y ListView responde a deslizamientos para desencadenar el desplazamiento. Si no estás usando esos widgets, pero quieres el efecto de "salpicadura de tinta" (ink splash) al tocar, puedes usar InkWell.

Desambiguación de gestos

#

En una ubicación dada en la pantalla, puede haber múltiples detectores de gestos. Por ejemplo:

  • Un ListTile tiene un reconocedor de toque que responde a todo el ListTile, y uno anidado alrededor de un botón de icono final. El rectángulo de pantalla del icono final ahora está cubierto por dos reconocedores de gestos que necesitan negociar quién maneja el gesto si resulta ser un toque.
  • Un solo GestureDetector cubre un área de pantalla configurada para manejar múltiples gestos, como una presión prolongada y un toque. El reconocedor de toque debe negociar ahora con el reconocedor de presión prolongada cuando el usuario toca esa parte de la pantalla. Dependiendo de lo que suceda a continuación con ese puntero, uno de los dos reconocedores recibe el gesto, o ninguno recibe el gesto si el usuario realiza algo que no es ni un toque ni una presión prolongada.

Todos estos detectores de gestos escuchan el flujo de eventos de puntero a medida que pasan e intentan reconocer gestos específicos. El widget GestureDetector decide qué gestos intentar reconocer en función de cuáles de sus callbacks no son nulos.

Cuando hay más de un reconocedor de gestos para un puntero dado en la pantalla, el framework desambigua qué gesto pretende hacer el usuario haciendo que cada reconocedor se una a la arena de gestos (gesture arena). La arena de gestos determina qué gesto gana utilizando las siguientes reglas:

  • En cualquier momento, un reconocedor puede eliminarse a sí mismo y salir de la arena. Si solo queda un reconocedor en la arena, ese reconocedor gana.

  • En cualquier momento, un reconocedor puede declararse ganador, haciendo que todos los reconocedores restantes pierdan.

Por ejemplo, al desambiguar el arrastre horizontal y vertical, ambos reconocedores entran en la arena cuando reciben el evento de presión del puntero. Los reconocedores observan los eventos de movimiento del puntero. Si el usuario mueve el puntero más de cierto número de píxeles lógicos horizontalmente, el reconocedor horizontal declara la victoria y el gesto se interpreta como un arrastre horizontal. De manera similar, si el usuario se mueve más de un cierto número de píxeles lógicos verticalmente, el reconocedor vertical se declara ganador.

La arena de gestos es beneficiosa cuando solo hay un reconocedor de arrastre horizontal (o vertical). En ese caso, solo hay un reconocedor en la arena y el arrastre horizontal se reconoce de inmediato, lo que significa que el primer píxel de movimiento horizontal puede tratarse como un arrastre y el usuario no necesitará esperar por más desambiguación de gestos.