Tutorial: Uso de la entrada táctil en Xamarin.iOS
En este tutorial se muestra cómo escribir código que responda a diferentes tipos de eventos táctiles. Cada ejemplo se incluye en una pantalla independiente:
- Ejemplos táctiles: cómo responder a eventos táctiles.
- Ejemplos de reconocedor de gestos: cómo usar reconocedores de gestos integrados.
- Ejemplo de reconocedor de gestos personalizados: cómo compilar un reconocedor de gestos personalizados.
Cada sección contiene instrucciones para escribir el código desde cero.
Siga las instrucciones siguientes para agregar código al guión gráfico y obtenga información sobre los diferentes tipos de eventos táctiles disponibles en iOS.
Ejemplos táctiles
En este ejemplo, mostraremos algunas de las API táctiles. Siga estos pasos para agregar el código necesario e implementar eventos táctiles:
Abra el proyectoTouch_Start. En primer lugar, ejecute el proyecto para asegurarse de que todo está bien y toque el botón Ejemplos táctiles. Debería ver una pantalla similar a la siguiente (aunque ninguno de los botones funcionará):
Edite el archivo TouchViewController.cs y agregue las dos variables de instancia siguientes a la clase
TouchViewController
:#region Private Variables private bool imageHighlighted = false; private bool touchStartedInside; #endregion
Implemente el método
TouchesBegan
como se muestra a continuación:public override void TouchesBegan(NSSet touches, UIEvent evt) { base.TouchesBegan(touches, evt); // If Multitouch is enabled, report the number of fingers down TouchStatus.Text = string.Format ("Number of fingers {0}", touches.Count); // Get the current touch UITouch touch = touches.AnyObject as UITouch; if (touch != null) { // Check to see if any of the images have been touched if (TouchImage.Frame.Contains(touch.LocationInView(TouchView))) { // Fist image touched TouchImage.Image = UIImage.FromBundle("TouchMe_Touched.png"); TouchStatus.Text = "Touches Began"; } else if (touch.TapCount == 2 && DoubleTouchImage.Frame.Contains(touch.LocationInView(TouchView))) { // Second image double-tapped, toggle bitmap if (imageHighlighted) { DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe.png"); TouchStatus.Text = "Double-Tapped Off"; } else { DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe_Highlighted.png"); TouchStatus.Text = "Double-Tapped On"; } imageHighlighted = !imageHighlighted; } else if (DragImage.Frame.Contains(touch.LocationInView(View))) { // Third image touched, prepare to drag touchStartedInside = true; } } }
Este método funciona comprobando si existe un objeto
UITouch
y, si existe, realiza alguna acción en función de dónde se produjo la función táctil:- Dentro de TouchImage: muestra el texto
Touches Began
en una etiqueta y cambia la imagen. - Dentro de DoubleTouchImage: cambia la imagen que se muestra si el gesto fue una pulsación doble.
- Dentro de DragImage: establece una marca que indica que se ha iniciado la función táctil. El método
TouchesMoved
usará esta marca para determinar siDragImage
se debe mover alrededor de la pantalla o no, como veremos en el paso siguiente.
El código anterior solo se ocupa de toques individuales, no hay ningún comportamiento si el usuario mueve su dedo en la pantalla. Para responder al movimiento, implemente
TouchesMoved
como se muestra en el código siguiente:public override void TouchesMoved(NSSet touches, UIEvent evt) { base.TouchesMoved(touches, evt); // get the touch UITouch touch = touches.AnyObject as UITouch; if (touch != null) { //==== IMAGE TOUCH if (TouchImage.Frame.Contains(touch.LocationInView(TouchView))) { TouchStatus.Text = "Touches Moved"; } //==== IMAGE DRAG // check to see if the touch started in the drag me image if (touchStartedInside) { // move the shape float offsetX = touch.PreviousLocationInView(View).X - touch.LocationInView(View).X; float offsetY = touch.PreviousLocationInView(View).Y - touch.LocationInView(View).Y; DragImage.Frame = new RectangleF(new PointF(DragImage.Frame.X - offsetX, DragImage.Frame.Y - offsetY), DragImage.Frame.Size); } } }
Este método obtiene un objeto
UITouch
y, a continuación, comprueba dónde se produjo el contacto. Si el toque se produjo enTouchImage
, el texto Touches Moved (Toques movidos) se muestra en la pantalla.Si
touchStartedInside
es cierto, sabemos que el usuario tiene el dedo enDragImage
y lo está moviendo. El código se moveráDragImage
a medida que el usuario mueve el dedo alrededor de la pantalla.- Dentro de TouchImage: muestra el texto
Necesitamos controlar el caso cuando el usuario levanta su dedo fuera de la pantalla, o iOS cancela el evento táctil. Para ello, implementaremos
TouchesEnded
yTouchesCancelled
como se muestra a continuación:public override void TouchesCancelled(NSSet touches, UIEvent evt) { base.TouchesCancelled(touches, evt); // reset our tracking flags touchStartedInside = false; TouchImage.Image = UIImage.FromBundle("TouchMe.png"); TouchStatus.Text = ""; } public override void TouchesEnded(NSSet touches, UIEvent evt) { base.TouchesEnded(touches, evt); // get the touch UITouch touch = touches.AnyObject as UITouch; if (touch != null) { //==== IMAGE TOUCH if (TouchImage.Frame.Contains(touch.LocationInView(TouchView))) { TouchImage.Image = UIImage.FromBundle("TouchMe.png"); TouchStatus.Text = "Touches Ended"; } } // reset our tracking flags touchStartedInside = false; }
Ambos métodos restablecerán la marca
touchStartedInside
a false.TouchesEnded
también mostraráTouchesEnded
en la pantalla.En este momento, la pantalla Ejemplos táctiles ha finalizado. Observe cómo cambia la pantalla a medida que interactúa con cada una de las imágenes, como se muestra en la captura de pantalla siguiente:
Ejemplos de reconocedor de gestos
En la sección anterior se mostró cómo arrastrar un objeto alrededor de la pantalla mediante eventos táctiles. En esta sección nos desharemos de los eventos táctiles y se mostrará cómo usar los siguientes reconocedores de gestos:
- El
UIPanGestureRecognizer
para arrastrar una imagen alrededor de la pantalla. - El
UITapGestureRecognizer
para responder a pulsaciones dobles en la pantalla.
Siga estos pasos para implementar reconocedores de gestos:
Edite el archivo GestureViewController.cs y agregue la siguiente variable de instancia:
#region Private Variables private bool imageHighlighted = false; private RectangleF originalImageFrame = RectangleF.Empty; #endregion
Necesitamos esta variable de instancia para realizar un seguimiento de la ubicación anterior de la imagen. El reconocedor de gestos panorámico usará el valor
originalImageFrame
para calcular el desplazamiento necesario para volver a dibujar la imagen en la pantalla.Agregue el método siguiente al controlador:
private void WireUpDragGestureRecognizer() { // Create a new tap gesture UIPanGestureRecognizer gesture = new UIPanGestureRecognizer(); // Wire up the event handler (have to use a selector) gesture.AddTarget(() => HandleDrag(gesture)); // to be defined // Add the gesture recognizer to the view DragImage.AddGestureRecognizer(gesture); }
Este código crea una instancia de un
UIPanGestureRecognizer
y lo agrega a una vista. Observe que asignamos un destino al gesto en forma del métodoHandleDrag
: este método se proporciona en el paso siguiente.Para implementar HandleDrag, agregue el código siguiente al controlador:
private void HandleDrag(UIPanGestureRecognizer recognizer) { // If it's just began, cache the location of the image if (recognizer.State == UIGestureRecognizerState.Began) { originalImageFrame = DragImage.Frame; } // Move the image if the gesture is valid if (recognizer.State != (UIGestureRecognizerState.Cancelled | UIGestureRecognizerState.Failed | UIGestureRecognizerState.Possible)) { // Move the image by adding the offset to the object's frame PointF offset = recognizer.TranslationInView(DragImage); RectangleF newFrame = originalImageFrame; newFrame.Offset(offset.X, offset.Y); DragImage.Frame = newFrame; } }
El código anterior comprobará primero el estado del reconocedor de gestos y, a continuación, moverá la imagen alrededor de la pantalla. Con este código en su lugar, el controlador ahora admite que se arrastre una imagen alrededor de la pantalla.
Agregue un
UITapGestureRecognizer
que cambiará la imagen que se va a mostrar en DoubleTouchImage. Agregue el método siguiente al controladorGestureViewController
:private void WireUpTapGestureRecognizer() { // Create a new tap gesture UITapGestureRecognizer tapGesture = null; // Report touch Action action = () => { TouchStatus.Text = string.Format("Image touched at: {0}",tapGesture.LocationOfTouch(0, DoubleTouchImage)); // Toggle the image if (imageHighlighted) { DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe.png"); } else { DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe_Highlighted.png"); } imageHighlighted = !imageHighlighted; }; tapGesture = new UITapGestureRecognizer(action); // Configure it tapGesture.NumberOfTapsRequired = 2; // Add the gesture recognizer to the view DoubleTouchImage.AddGestureRecognizer(tapGesture); }
Este código es muy similar al código del
UIPanGestureRecognizer
, pero en lugar de usar un delegado para un destino, estamos usando unAction
.Lo último que debemos hacer es modificar
ViewDidLoad
para que llame a los métodos que acabamos de agregar. Cambie ViewDidLoad para que se parezca al código siguiente:public override void ViewDidLoad() { base.ViewDidLoad(); Title = "Gesture Recognizers"; // Save initial state originalImageFrame = DragImage.Frame; WireUpTapGestureRecognizer(); WireUpDragGestureRecognizer(); }
Observe también que inicializamos el valor de
originalImageFrame
.Ejecute la aplicación e interactúe con las dos imágenes. La siguiente captura de pantalla muestra un ejemplo de estas interacciones:
Reconocedor de gestos personalizados
En esta sección se aplicarán los conceptos de las secciones anteriores para crear un reconocedor de gestos personalizados. El reconocedor de gestos personalizados reconocerá las subclases UIGestureRecognizer
y reconocerá cuando el usuario dibuje una "V" en la pantalla y, a continuación, alternará un mapa de bits. La captura de pantalla siguiente es un ejemplo de esta pantalla:
Siga estos pasos para crear un reconocedor de gestos personalizados:
Agregue una nueva clase al proyecto denominado
CheckmarkGestureRecognizer
y haga que tenga un aspecto similar al siguiente:using System; using CoreGraphics; using Foundation; using UIKit; namespace Touch { public class CheckmarkGestureRecognizer : UIGestureRecognizer { #region Private Variables private CGPoint midpoint = CGPoint.Empty; private bool strokeUp = false; #endregion #region Override Methods /// <summary> /// Called when the touches end or the recognizer state fails /// </summary> public override void Reset() { base.Reset(); strokeUp = false; midpoint = CGPoint.Empty; } /// <summary> /// Is called when the fingers touch the screen. /// </summary> public override void TouchesBegan(NSSet touches, UIEvent evt) { base.TouchesBegan(touches, evt); // we want one and only one finger if (touches.Count != 1) { base.State = UIGestureRecognizerState.Failed; } Console.WriteLine(base.State.ToString()); } /// <summary> /// Called when the touches are cancelled due to a phone call, etc. /// </summary> public override void TouchesCancelled(NSSet touches, UIEvent evt) { base.TouchesCancelled(touches, evt); // we fail the recognizer so that there isn't unexpected behavior // if the application comes back into view base.State = UIGestureRecognizerState.Failed; } /// <summary> /// Called when the fingers lift off the screen /// </summary> public override void TouchesEnded(NSSet touches, UIEvent evt) { base.TouchesEnded(touches, evt); // if (base.State == UIGestureRecognizerState.Possible && strokeUp) { base.State = UIGestureRecognizerState.Recognized; } Console.WriteLine(base.State.ToString()); } /// <summary> /// Called when the fingers move /// </summary> public override void TouchesMoved(NSSet touches, UIEvent evt) { base.TouchesMoved(touches, evt); // if we haven't already failed if (base.State != UIGestureRecognizerState.Failed) { // get the current and previous touch point CGPoint newPoint = (touches.AnyObject as UITouch).LocationInView(View); CGPoint previousPoint = (touches.AnyObject as UITouch).PreviousLocationInView(View); // if we're not already on the upstroke if (!strokeUp) { // if we're moving down, just continue to set the midpoint at // whatever point we're at. when we start to stroke up, it'll stick // as the last point before we upticked if (newPoint.X >= previousPoint.X && newPoint.Y >= previousPoint.Y) { midpoint = newPoint; } // if we're stroking up (moving right x and up y [y axis is flipped]) else if (newPoint.X >= previousPoint.X && newPoint.Y <= previousPoint.Y) { strokeUp = true; } // otherwise, we fail the recognizer else { base.State = UIGestureRecognizerState.Failed; } } } Console.WriteLine(base.State.ToString()); } #endregion } }
Se llama al método Reset cuando la propiedad
State
cambia aRecognized
oEnded
. Este es el momento de restablecer cualquier estado interno establecido en el reconocedor de gestos personalizados. Ahora la clase puede iniciarse de nuevo la próxima vez que el usuario interactúe con la aplicación y esté listo para volver a intentar reconocer el gesto.Ahora que hemos definido un reconocedor de gestos personalizados (
CheckmarkGestureRecognizer
), edite el archivo CustomGestureViewController.cs y agregue las dos variables de instancia siguientes:#region Private Variables private bool isChecked = false; private CheckmarkGestureRecognizer checkmarkGesture; #endregion
Para crear una instancia y configurar nuestro reconocedor de gestos, agregue el siguiente método al controlador:
private void WireUpCheckmarkGestureRecognizer() { // Create the recognizer checkmarkGesture = new CheckmarkGestureRecognizer(); // Wire up the event handler checkmarkGesture.AddTarget(() => { if (checkmarkGesture.State == (UIGestureRecognizerState.Recognized | UIGestureRecognizerState.Ended)) { if (isChecked) { CheckboxImage.Image = UIImage.FromBundle("CheckBox_Unchecked.png"); } else { CheckboxImage.Image = UIImage.FromBundle("CheckBox_Checked.png"); } isChecked = !isChecked; } }); // Add the gesture recognizer to the view View.AddGestureRecognizer(checkmarkGesture); }
Edite
ViewDidLoad
para que llame aWireUpCheckmarkGestureRecognizer
, como se muestra en el siguiente fragmento de código:public override void ViewDidLoad() { base.ViewDidLoad(); // Wire up the gesture recognizer WireUpCheckmarkGestureRecognizer(); }
Ejecute la aplicación e intente dibujar una "V" en la pantalla. Debería ver que la imagen que se muestra cambia, como se muestra en las capturas de pantalla siguientes:
Las tres secciones anteriores mostraron diferentes formas de responder a eventos táctiles en iOS: mediante eventos táctiles, reconocedores de gestos integrados o con un reconocedor de gestos personalizados.