Share via


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 :

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 :

  1. 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) :

    Exemple d’exécution d’application avec des boutons non fonctionnel

  2. 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
    
  3. 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 si DragImage 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, TouchImagele texte Touches déplacées s’affiche sur l’écran.

    Si touchStartedInside c’est vrai, nous savons que l’utilisateur a son doigt dessus DragImage et le déplace. Le code se déplace DragImage à mesure que l’utilisateur déplace son doigt autour de l’écran.

  4. 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 et TouchesCancelled 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’affiche TouchesEnded également à l’écran.

  5. À 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 :

    Écran de démarrage de l’application

    Écran après que l’utilisateur fait glisser un bouton

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 :

  1. 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.

  2. 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éthode HandleDrag : cette méthode est fournie à l’étape suivante.

  3. 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.

  4. Ajoutez un UITapGestureRecognizer élément qui modifiera l’image affichée dans DoubleTouchImage. Ajoutez la méthode suivante au GestureViewController 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 un Action.

  5. 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.

  6. Exécutez l’application et interagissez avec les deux images. La capture d’écran suivante est un exemple de ces interactions :

    Cette capture d’écran montre une interaction glisser

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 UIGestureRecognizermouvement 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 :

L’application reconnaît quand l’utilisateur dessine un V sur l’écran

Procédez comme suit pour créer un module de reconnaissance de mouvement personnalisé :

  1. Ajoutez une nouvelle classe au projet nommé CheckmarkGestureRecognizeret 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’autre Recognized ou Ended. 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.

  2. 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
    
  3. 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);
    }
    
  4. Modifiez ViewDidLoad pour qu’elle appelle WireUpCheckmarkGestureRecognizer, comme indiqué dans l’extrait de code suivant :

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
    
        // Wire up the gesture recognizer
        WireUpCheckmarkGestureRecognizer();
    }
    
  5. 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 :

    Bouton case activée ed

    Bouton non case activée ed

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é.