Procedura dettagliata: Uso del tocco in Xamarin.iOS

Questa procedura dettagliata illustra come scrivere codice che risponde a diversi tipi di eventi di tocco. Ogni esempio è contenuto in una schermata separata:

Ogni sezione contiene istruzioni per scrivere il codice da zero.

Seguire le istruzioni seguenti per aggiungere codice allo storyboard e informazioni sui diversi tipi di eventi di tocco disponibili in iOS.

Esempi di tocco

In questo esempio verranno illustrate alcune delle API di tocco. Seguire questa procedura per aggiungere il codice necessario per implementare gli eventi di tocco:

  1. Aprire il Touch_Start del progetto. Eseguire prima di tutto il progetto per assicurarsi che tutto sia corretto e toccare il pulsante Touch Samples (Esempi di tocco). Verrà visualizzata una schermata simile alla seguente (anche se nessuno dei pulsanti funzionerà):

    App di esempio eseguita con pulsanti non funzionanti

  2. Modificare il file TouchViewController.cs e aggiungere le due variabili di istanza seguenti alla classe TouchViewController:

    #region Private Variables
    private bool imageHighlighted = false;
    private bool touchStartedInside;
    #endregion
    
  3. Implementare il TouchesBegan metodo , come illustrato nel codice seguente:

    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;
            }
        }
    }
    

    Questo metodo funziona controllando la presenza di un UITouch oggetto e, se esistente, esegue alcune azioni in base alla posizione in cui si è verificato il tocco:

    • All'interno di TouchImage : visualizzare il testo Touches Began in un'etichetta e modificare l'immagine.
    • All'interno di DoubleTouchImage : modificare l'immagine visualizzata se il movimento è stato doppio tocco.
    • All'interno di DragImage : impostare un flag che indica che il tocco è stato avviato. Il metodo TouchesMoved userà questo flag per determinare se DragImage deve essere spostato sullo schermo o meno, come si vedrà nel passaggio successivo.

    Il codice precedente riguarda solo i singoli tocchi, non esiste ancora alcun comportamento se l'utente sta spostando il dito sullo schermo. Per rispondere allo spostamento, implementare TouchesMoved come illustrato nel codice seguente:

    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);
            }
        }
    }
    

    Questo metodo ottiene un UITouch oggetto e quindi verifica dove si è verificato il tocco. Se il tocco si è verificato in TouchImage, il testo Touches Moved viene visualizzato sullo schermo.

    Se touchStartedInside è true, sappiamo che l'utente ha il dito su DragImage e lo sta spostando. Il codice verrà spostato DragImage quando l'utente sposta il dito intorno allo schermo.

  4. È necessario gestire il caso quando l'utente solleva il dito dallo schermo oppure iOS annulla l'evento di tocco. A tale scopo, verrà implementato TouchesEnded e TouchesCancelled come illustrato di seguito:

    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;
    }
    

    Entrambi questi metodi reimpostano il touchStartedInside flag su false. TouchesEnded verrà visualizzata TouchesEnded anche sullo schermo.

  5. A questo punto, la schermata Touch Samples (Esempi di tocco) è terminata. Si noti che la schermata cambia durante l'interazione con ognuna delle immagini, come illustrato nello screenshot seguente:

    Schermata dell'app iniziale

    Schermata dopo che l'utente trascina un pulsante

Esempi di riconoscimento dei movimenti

La sezione precedente ha illustrato come trascinare un oggetto intorno allo schermo usando gli eventi di tocco. In questa sezione si elimineranno gli eventi di tocco e si mostrerà come usare i seguenti riconoscitori di movimento:

  • Oggetto UIPanGestureRecognizer per il trascinamento di un'immagine sullo schermo.
  • Oggetto UITapGestureRecognizer per rispondere a doppio tocco sullo schermo.

Seguire questa procedura per implementare i riconoscitori dei movimenti:

  1. Modificare il file GestureViewController.cs e aggiungere la variabile di istanza seguente:

    #region Private Variables
    private bool imageHighlighted = false;
    private RectangleF originalImageFrame = RectangleF.Empty;
    #endregion
    

    Questa variabile di istanza è necessaria per tenere traccia della posizione precedente dell'immagine. Il riconoscimento movimento panoramica userà il originalImageFrame valore per calcolare l'offset necessario per ridisegnare l'immagine sullo schermo.

  2. Aggiungere il metodo seguente al controller:

    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);
    }
    

    Questo codice crea un'istanza UIPanGestureRecognizer di e lo aggiunge a una visualizzazione. Si noti che si assegna una destinazione al movimento sotto forma di metodo HandleDrag . Questo metodo viene fornito nel passaggio successivo.

  3. Per implementare HandleDrag, aggiungere il codice seguente al controller:

    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;
        }
    }
    

    Il codice precedente controlla prima lo stato del riconoscimento movimento e quindi sposta l'immagine sullo schermo. Con questo codice sul posto, il controller può ora supportare il trascinamento dell'immagine intorno allo schermo.

  4. Aggiungere un oggetto UITapGestureRecognizer che modificherà l'immagine visualizzata in DoubleTouchImage. Aggiungere il metodo seguente al GestureViewController controller:

    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);
    }
    

    Questo codice è molto simile al codice per ma UIPanGestureRecognizer invece di usare un delegato per una destinazione in cui viene usato un oggetto Action.

  5. L'ultima operazione da eseguire è modificare ViewDidLoad in modo che chiami i metodi appena aggiunti. Modificare ViewDidLoad in modo che sia simile al codice seguente:

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
    
        Title = "Gesture Recognizers";
    
        // Save initial state
        originalImageFrame = DragImage.Frame;
    
        WireUpTapGestureRecognizer();
        WireUpDragGestureRecognizer();
    }
    

    Si noti anche che si inizializza il valore di originalImageFrame.

  6. Eseguire l'applicazione e interagire con le due immagini. Lo screenshot seguente è un esempio di queste interazioni:

    Questo screenshot mostra un'interazione di trascinamento

Riconoscimento movimento personalizzato

In questa sezione verranno applicati i concetti delle sezioni precedenti per creare un riconoscimento movimento personalizzato. Il riconoscimento movimento personalizzato sottoclasserà UIGestureRecognizere riconoscerà quando l'utente disegna una "V" sullo schermo e quindi attiva o disattiva una bitmap. Lo screenshot seguente è un esempio di questa schermata:

L'app riconoscerà quando l'utente disegna una V sullo schermo

Per creare un riconoscimento movimento personalizzato, seguire questa procedura:

  1. Aggiungere una nuova classe al progetto denominato CheckmarkGestureRecognizere renderla simile al codice seguente:

    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
        }
    }
    

    Il metodo Reset viene chiamato quando la State proprietà viene modificata in Recognized o Ended. Questo è il momento di reimpostare qualsiasi stato interno impostato nel riconoscimento movimenti personalizzato. Ora la classe può iniziare nuovamente la prossima volta che l'utente interagisce con l'applicazione ed essere pronto a provare a riconoscere il movimento.

  2. Ora che è stato definito un riconoscimento movimento personalizzato (CheckmarkGestureRecognizer) modificare il file CustomGestureViewController.cs e aggiungere le due variabili di istanza seguenti:

    #region Private Variables
    private bool isChecked = false;
    private CheckmarkGestureRecognizer checkmarkGesture;
    #endregion
    
  3. Per creare un'istanza e configurare il riconoscimento dei movimenti, aggiungere il metodo seguente al controller:

    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. Modificare ViewDidLoad in modo che chiami WireUpCheckmarkGestureRecognizer, come illustrato nel frammento di codice seguente:

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
    
        // Wire up the gesture recognizer
        WireUpCheckmarkGestureRecognizer();
    }
    
  5. Eseguire l'applicazione e provare a disegnare una "V" sullo schermo. Verrà visualizzata la modifica dell'immagine, come illustrato negli screenshot seguenti:

    Pulsante selezionato

    Pulsante deselezionato

Le tre sezioni precedenti illustrano diversi modi per rispondere agli eventi di tocco in iOS: uso di eventi di tocco, riconoscitori di movimenti predefiniti o con un riconoscimento movimento personalizzato.