Procédure pas à pas : utilisation de Touch dans Xamarin.iOS
Cette procédure pas à pas montre comment écrire du code qui répond à différents types d’événements tactiles. Chaque exemple est contenu dans un écran distinct :
- Exemples tactiles : comment répondre aux événements tactiles.
- Exemples de reconnaissance de mouvement : comment utiliser des modules de reconnaissance de mouvements intégrés.
- Exemple Custom Gesture Recognizer : comment créer un module de reconnaissance de mouvement personnalisé.
Chaque section contient des instructions pour écrire le code à partir de zéro.
Suivez les instructions ci-dessous pour ajouter du code au storyboard et en savoir plus sur les différents types d’événements tactiles disponibles dans iOS.
Exemples tactiles
Dans cet exemple, nous allons illustrer certaines DES API tactiles. Procédez comme suit pour ajouter le code requis pour implémenter des événements tactiles :
Ouvrez le projet Touch_Start. Tout d’abord, exécutez le projet pour vous assurer que tout est correct et appuyez sur le bouton Exemples tactiles. Vous devriez voir un écran similaire à ce qui suit (bien qu’aucun des boutons ne fonctionne) :
Modifiez le fichier TouchViewController.cs et ajoutez les deux variables d’instance suivantes à la classe
TouchViewController
:#region Private Variables private bool imageHighlighted = false; private bool touchStartedInside; #endregion
Implémentez la
TouchesBegan
méthode, comme indiqué dans le code ci-dessous :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; } } }
Cette méthode fonctionne en case activée pour un
UITouch
objet et, s’il existe, effectuez une action en fonction de l’endroit où l’interaction s’est produite :- À l’intérieur de TouchImage , affichez le texte
Touches Began
dans une étiquette et modifiez l’image. - À l’intérieur de DoubleTouchImage , modifiez l’image affichée si le mouvement a été appuyé deux fois.
- À l’intérieur de DragImage , définissez un indicateur indiquant que l’interaction tactile a démarré. La méthode
TouchesMoved
utilise cet indicateur pour déterminer siDragImage
elle doit être déplacée autour de l’écran ou non, comme nous le verrons à l’étape suivante.
Le code ci-dessus traite uniquement des touches individuelles, il n’y a toujours aucun comportement si l’utilisateur déplace son doigt sur l’écran. Pour répondre au mouvement, implémentez
TouchesMoved
comme indiqué dans le code ci-dessous :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); } } }
Cette méthode obtient un
UITouch
objet, puis case activée pour voir où l’interaction tactile s’est produite. Si l’interaction tactile s’est produite,TouchImage
le texte Touches déplacées s’affiche sur l’écran.Si
touchStartedInside
c’est vrai, nous savons que l’utilisateur a son doigt dessusDragImage
et le déplace. Le code se déplaceDragImage
à mesure que l’utilisateur déplace son doigt autour de l’écran.- À l’intérieur de TouchImage , affichez le texte
Nous devons gérer le cas lorsque l’utilisateur lève son doigt hors de l’écran, ou iOS annule l’événement tactile. Pour cela, nous allons implémenter
TouchesEnded
etTouchesCancelled
comme indiqué ci-dessous :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; }
Ces deux méthodes réinitialisent l’indicateur
touchStartedInside
sur false.TouchesEnded
s’afficheTouchesEnded
également à l’écran.À ce stade, l’écran Exemples tactiles est terminé. Notez comment l’écran change lorsque vous interagissez avec chacune des images, comme illustré dans la capture d’écran suivante :
Exemples de reconnaissance de mouvement
La section précédente a montré comment faire glisser un objet autour de l’écran à l’aide d’événements tactiles. Dans cette section, nous allons nous débarrasser des événements tactiles et montrer comment utiliser les modules de reconnaissance de mouvement suivants :
- Pour
UIPanGestureRecognizer
faire glisser une image autour de l’écran. - Réponse
UITapGestureRecognizer
aux appuis doubles sur l’écran.
Procédez comme suit pour implémenter des modules de reconnaissance de mouvement :
Modifiez le fichier GestureViewController.cs et ajoutez la variable d’instance suivante :
#region Private Variables private bool imageHighlighted = false; private RectangleF originalImageFrame = RectangleF.Empty; #endregion
Nous avons besoin de cette variable d’instance pour suivre l’emplacement précédent de l’image. Le module de reconnaissance panoramique utilise la
originalImageFrame
valeur pour calculer le décalage nécessaire pour redessiner l’image à l’écran.Ajoutez la méthode suivante au contrôleur :
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); }
Ce code instancie une
UIPanGestureRecognizer
instance et l’ajoute à une vue. Notez que nous affectons une cible au mouvement sous la forme de la méthodeHandleDrag
: cette méthode est fournie à l’étape suivante.Pour implémenter HandleDrag, ajoutez le code suivant au contrôleur :
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; } }
Le code ci-dessus case activée d’abord l’état du module de reconnaissance des mouvements, puis déplace l’image autour de l’écran. Avec ce code en place, le contrôleur peut désormais prendre en charge le glissement d’une image autour de l’écran.
Ajoutez un
UITapGestureRecognizer
élément qui modifiera l’image affichée dans DoubleTouchImage. Ajoutez la méthode suivante auGestureViewController
contrôleur :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); }
Ce code est très similaire au code pour le
UIPanGestureRecognizer
mais au lieu d’utiliser un délégué pour une cible, nous utilisons unAction
.La dernière chose à faire est de modifier
ViewDidLoad
afin qu’elle appelle les méthodes que nous venons d’ajouter. Modifiez ViewDidLoad pour qu’il ressemble au code suivant :public override void ViewDidLoad() { base.ViewDidLoad(); Title = "Gesture Recognizers"; // Save initial state originalImageFrame = DragImage.Frame; WireUpTapGestureRecognizer(); WireUpDragGestureRecognizer(); }
Notez également que nous initialisons la valeur de
originalImageFrame
.Exécutez l’application et interagissez avec les deux images. La capture d’écran suivante est un exemple de ces interactions :
Module de reconnaissance de mouvement personnalisé
Dans cette section, nous allons appliquer les concepts des sections précédentes pour créer un module de reconnaissance de mouvement personnalisé. Le module de reconnaissance de UIGestureRecognizer
mouvement personnalisé sous-classe, et reconnaît quand l’utilisateur dessine un « V » à l’écran, puis bascule une bitmap. La capture d’écran suivante est un exemple de cet écran :
Procédez comme suit pour créer un module de reconnaissance de mouvement personnalisé :
Ajoutez une nouvelle classe au projet nommé
CheckmarkGestureRecognizer
et faites-le ressembler au code suivant :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 } }
La méthode Reset est appelée lorsque la
State
propriété passe à l’une ou l’autreRecognized
ouEnded
. Il s’agit du moment de réinitialiser tout jeu d’état interne dans le module de reconnaissance de mouvement personnalisé. À présent, la classe peut commencer à démarrer à nouveau la prochaine fois que l’utilisateur interagit avec l’application et être prêt à réessayer de reconnaître le mouvement.Maintenant que nous avons défini un module de reconnaissance de mouvement personnalisé (
CheckmarkGestureRecognizer
) modifiez le fichier CustomGestureViewController.cs et ajoutez les deux variables d’instance suivantes :#region Private Variables private bool isChecked = false; private CheckmarkGestureRecognizer checkmarkGesture; #endregion
Pour instancier et configurer notre module de reconnaissance de mouvement, ajoutez la méthode suivante au contrôleur :
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); }
Modifiez
ViewDidLoad
pour qu’elle appelleWireUpCheckmarkGestureRecognizer
, comme indiqué dans l’extrait de code suivant :public override void ViewDidLoad() { base.ViewDidLoad(); // Wire up the gesture recognizer WireUpCheckmarkGestureRecognizer(); }
Exécutez l’application et essayez de dessiner un « V » à l’écran. Vous devez voir l’image affichée changer, comme illustré dans les captures d’écran suivantes :
Les trois sections ci-dessus ont montré différentes façons de répondre aux événements tactiles dans iOS : à l’aide d’événements tactiles, de modules de reconnaissance de mouvements intégrés ou d’un module de reconnaissance de mouvements personnalisé.