Eventos y gestos táctiles en Xamarin.iOS
Es importante comprender los eventos táctiles y las API táctiles en una aplicación de iOS, ya que son fundamentales para todas las interacciones físicas con el dispositivo. Todas las interacciones táctiles implican un objeto UITouch
. En este artículo, veremos cómo usar la clase UITouch
y sus API para admitir la entrada táctil. Más adelante, ampliaremos nuestro conocimiento para aprender a admitir gestos.
Habilitación de la entrada táctil
Los controles en UIKit
—aquellos subclasificados de UIControl— son tan dependientes de la interacción del usuario que tienen gestos incorporados en UIKit y por lo tanto no es necesario habilitar la entrada táctil. Ya está habilitado.
Sin embargo, muchas de las vistas de UIKit
no tienen la funcionalidad táctil habilitada de forma predeterminada. Hay dos maneras de habilitar la entrada táctil en un control. La primera forma es activar la casilla Interacción del usuario habilitada en el Panel de propiedades del Diseñador de iOS, como se muestra en la captura de pantalla siguiente:
También podemos usar un controlador para establecer la propiedad UserInteractionEnabled
en true en una clase UIView
. Esto es necesario si la interfaz de usuario se crea en el código.
Un ejemplo de esto es la siguiente línea de código:
imgTouchMe.UserInteractionEnabled = true;
Eventos de funciones táctiles
Hay tres fases de función táctil que se producen cuando el usuario toca la pantalla, mueve el dedo o quita el dedo. Estos métodos se definen en UIResponder
, que es la clase base para UIView. iOS invalidará los métodos asociados en UIView
y UIViewController
para controlar la función táctil:
TouchesBegan
: se le llama cuando la pantalla se toca por primera vez.TouchesMoved
: se le llama cuando cambia la ubicación de la entrada táctil a medida que el usuario desliza los dedos alrededor de la pantalla.TouchesEnded
oTouchesCancelled
: se llama aTouchesEnded
cuando los dedos del usuario se levantan de la pantalla. Se llama aTouchesCancelled
si iOS cancela la entrada táctil; por ejemplo, si un usuario desliza su dedo aleja el dedo de un botón para cancelar una pulsación.
Los eventos táctiles viajan de forma recursiva a través de la pila de UIViews para comprobar si el evento táctil está dentro de los límites de un objeto de vista. Esta tarea suele denominar prueba de posicionamiento. Primero se les llamará en el UIView
o UIViewController
superior y después se ejecutarán en el UIView
y UIViewControllers
inferiores en la jerarquía de vistas.
Se creará un objeto UITouch
cada vez que el usuario toque la pantalla. El objeto UITouch
incluye datos sobre la función táctil, como cuando se produjo el toque, donde se produjo, si la función táctil era un deslizamiento, etc. Los eventos táctiles se pasan a una propiedad de funciones táctiles, un NSSet
que contiene uno o varios toques. Podemos usar esta propiedad para obtener una referencia a un toque y determinar la respuesta de la aplicación.
Las clases que invalidan uno de los eventos táctiles deben llamar primero a la implementación base y, a continuación, obtener el objeto UITouch
asociado al evento. Para obtener una referencia a la primera entrada táctil, llame a la propiedad AnyObject
y conviértela en UITouch
como se muestra en el ejemplo siguiente:
public override void TouchesBegan (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
UITouch touch = touches.AnyObject as UITouch;
if (touch != null)
{
//code here to handle touch
}
}
iOS reconoce automáticamente los toques rápidos sucesivos en la pantalla y los recopilará como un solo toque en un solo objeto UITouch
. Esto hace que la comprobación de una pulsación doble sea tan fácil como comprobar la propiedad TapCount
, como se muestra en el código siguiente:
public override void TouchesBegan (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
UITouch touch = touches.AnyObject as UITouch;
if (touch != null)
{
if (touch.TapCount == 2)
{
// do something with the double touch.
}
}
}
Entrada multitáctil
La entrada multitáctil no está habilitado de forma predeterminada en los controles. Se puede habilitar en iOS Designer, como se muestra en la captura de pantalla siguiente:
También es posible establecer la entrada multitáctil mediante programación estableciendo la propiedad MultipleTouchEnabled
como se muestra en la siguiente línea de código:
imgTouchMe.MultipleTouchEnabled = true;
Para determinar cuántos dedos tocaron la pantalla, use la propiedad Count
en la propiedad UITouch
:
public override void TouchesBegan (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
lblNumberOfFingers.Text = "Number of fingers: " + touches.Count.ToString();
}
Determinación de la ubicación táctil
El método UITouch.LocationInView
devuelve un objeto CGPoint que contiene las coordenadas del toque dentro de una vista determinada. Además, podemos probar para ver si esa ubicación está dentro de un control llamando al método Frame.Contains
. En el siguiente fragmento de código se muestra un ejemplo:
if (this.imgTouchMe.Frame.Contains (touch.LocationInView (this.View)))
{
// the touch event happened inside the UIView imgTouchMe.
}
Ahora que tenemos una comprensión de los eventos táctiles en iOS, vamos a aprender sobre los reconocedores de gestos.
Reconocedores de gestos
Los reconocedores de gestos pueden simplificar y reducir considerablemente el esfuerzo de programación para admitir la entrada táctil en una aplicación. Los reconocedores de gestos de iOS agregan una serie de eventos táctiles en un solo evento táctil.
Xamarin.iOS proporciona la clase UIGestureRecognizer
como una clase base para los siguientes reconocedores de gestos integrados:
- UITapGestureRecognizer: esto es para una o varias pulsaciones.
- UIPinchGestureRecognizer: juntar y separar dedos.
- UIPanGestureRecognizer: desplazamiento lateral o arrastre.
- UISwipeGestureRecognizer: deslizamiento en cualquier dirección.
- UIRotationGestureRecognizer: giro de dos dedos en el sentido de las agujas del reloj o en sentido contrario.
- UILongPressGestureRecognizer: presión y mantenimiento, a veces denominado pulsación larga o clic largo.
El patrón básico para usar un reconocedor de gestos es el siguiente:
- Crear una instancia del reconocedor de gestos: en primer lugar, cree una instancia de una subclase
UIGestureRecognizer
. El objeto del que se cree la instancia estará asociado a una vista y se recogerá cuando se elimine la vista. No es necesario crear esta vista como una variable de nivel de clase. - Configurar cualquier configuración de gestos: el siguiente paso es configurar el reconocedor de gestos. Consulte la documentación de Xamarin sobre
UIGestureRecognizer
y sus subclases para obtener una lista de propiedades que se pueden establecer para controlar el comportamiento de una instanciaUIGestureRecognizer
. - Configurar el destino: debido a su herencia Objective-C, Xamarin.iOS no genera eventos cuando un reconocedor de gestos coincide con un gesto.
UIGestureRecognizer
tiene un método (AddTarget
) que puede aceptar un delegado anónimo o un selector Objective-C con el código que se va a ejecutar cuando el reconocedor de gestos hace una coincidencia. - Habilitar el reconocedor de gestos: al igual que con los eventos táctiles, los gestos solo se reconocen si se habilitan las interacciones táctiles.
- Agregar el reconocedor de gestos a la vista: el paso final consiste en agregar el gesto a una vista llamando a
View.AddGestureRecognizer
y pasándole un objeto reconocedor de gestos.
Consulte los ejemplos del reconocedor de gestos para obtener más información sobre cómo implementarlos en el código.
Cuando se llama al destino del gesto, se le pasará una referencia al gesto que se produjo. Esto permite que el destino del gesto obtenga información sobre el gesto que se produjo. La extensión de información disponible depende del tipo de reconocedor de gestos que se usó. Consulte la documentación de Xamarin para obtener información sobre los datos disponibles para cada subclase UIGestureRecognizer
.
Es importante recordar que una vez que se ha agregado un reconocedor de gestos a una vista, la vista (y las vistas debajo de ella) no recibirá ningún evento táctil. Para permitir eventos táctiles simultáneamente con gestos, la propiedad CancelsTouchesInView
debe establecerse en false, como se muestra en el código siguiente:
_tapGesture.Recognizer.CancelsTouchesInView = false;
Cada UIGestureRecognizer
tiene una propiedad State que proporciona información importante sobre el estado del reconocedor de gestos. Cada vez que cambia el valor de esta propiedad, iOS llamará al método de suscripción, lo que le proporcionará una actualización. Si un reconocedor de gestos personalizado nunca actualiza la propiedad State, nunca se llama al suscriptor, lo que hace que el reconocedor de gestos sea inútil.
Los gestos se pueden resumir como uno de los dos tipos:
- Discreto: estos gestos solo se activan la primera vez que se reconocen.
- Continuo: estos gestos se continúan activando siempre que se reconozcan.
Los reconocedores de gestos existen en uno de los estados siguientes:
- Posible: este es el estado inicial de todos los reconocedores de gestos. Este es el valor predeterminado de la propiedad State.
- Iniciado: cuando se reconoce por primera vez un gesto continuo, el estado se establece en Iniciado. Esto permite a los suscriptores diferenciar entre el momento en que se inicia el reconocimiento de gestos y el momento en que se modifica.
- Modificado: después de que un gesto continuo haya comenzado, pero no haya terminado, el estado se establecerá en Modificado cada vez que un toque se mueva o cambie, siempre y cuando siga dentro de los parámetros esperados del gesto.
- Cancelado: este estado se establecerá si el reconocedor pasó de Iniciado a Modificado, y luego los toques cambiaron de tal manera que ya no se ajustan al patrón del gesto.
- Reconocido : el estado se establecerá cuando el reconocedor de gestos coincida con un conjunto de toques e informará al suscriptor de que el gesto ha finalizado.
- Finalizado: se trata de un alias para el estado Reconocido.
- Error: cuando el reconocedor de gestos ya no puede coincidir con los toques que está escuchando, el estado cambiará a Error.
Xamarin.iOS representa estos valores en la enumeración UIGestureRecognizerState
.
Trabajo con varios gestos
De forma predeterminada, iOS no permite que los gestos predeterminados se ejecuten simultáneamente. En su lugar, cada reconocedor de gestos recibirá eventos táctiles en un orden no determinista. El siguiente fragmento de código ilustra cómo realizar una ejecución simultánea de un reconocedor de gestos:
gesture.ShouldRecognizeSimultaneously += (UIGestureRecognizer r) => { return true; };
También es posible deshabilitar un gesto en iOS. Hay dos propiedades de delegado que permiten a un reconocedor de gestos examinar el estado de una aplicación y los eventos táctiles actuales, para tomar decisiones sobre cómo y si se debe reconocer un gesto. Los dos eventos son:
- ShouldReceiveTouch: se llama a este delegado justo antes de que el reconocedor de gestos pase un evento táctil, y proporciona una oportunidad para examinar los toques y decidir qué toques se controlarán mediante el reconocedor de gestos.
- ShouldBegin: se le llama cuando un reconocedor intenta cambiar el estado de Posible a otro estado. Si devuelve false, el estado del reconocedor de gestos cambiará a Error.
Puedes anular estos métodos con un UIGestureRecognizerDelegate
fuertemente tipado, un delegado débil, o enlazar a través de la sintaxis del controlador de eventos, como se ilustra en el siguiente fragmento de código:
gesture.ShouldReceiveTouch += (UIGestureRecognizer r, UITouch t) => { return true; };
Por último, es posible poner en cola un reconocedor de gestos para que solo se ejecute correctamente si se produce un error en otro reconocedor de gestos. Por ejemplo, un reconocedor de gestos de un solo toque solo debería ejecutarse correctamente cuando se produzca un error en un reconocedor de gestos de doble toque. El siguiente fragmento de código proporciona un ejemplo de esto:
singleTapGesture.RequireGestureRecognizerToFail(doubleTapGesture);
Creación de un gesto personalizado
Aunque iOS proporciona algunos reconocedores de gestos predeterminados, puede ser necesario crear reconocedores de gestos personalizados en determinados casos. La creación de un reconocedor de gestos personalizado implica los pasos siguientes:
- Subclase
UIGestureRecognizer
. - Invalide los métodos de evento táctil adecuados.
- Propague el estado de reconocimiento a través de la propiedad State de la clase base.
Un ejemplo práctico de esto se tratará en el tutorial Uso del evento táctil en iOS.