Udostępnij za pośrednictwem


Przewodnik: używanie funkcji Touch na platformie Xamarin.iOS

W tym przewodniku pokazano, jak napisać kod, który reaguje na różne rodzaje zdarzeń dotykowych. Każdy przykład znajduje się na osobnym ekranie:

Każda sekcja zawiera instrukcje dotyczące pisania kodu od podstaw.

Postępuj zgodnie z poniższymi instrukcjami, aby dodać kod do scenorysu i dowiedzieć się więcej o różnych typach zdarzeń dotykowych dostępnych w systemie iOS.

Przykłady dotyku

W tym przykładzie przedstawimy niektóre interfejsy API dotyku. Wykonaj następujące kroki, aby dodać kod wymagany do zaimplementowania zdarzeń dotykowych:

  1. Otwórz Touch_Start projektu. Najpierw uruchom projekt, aby upewnić się, że wszystko jest w porządku, a następnie naciśnij przycisk Touch Samples (Próbki dotykowe). Powinien zostać wyświetlony ekran podobny do poniższego (chociaż żaden z przycisków nie będzie działać):

    Przykładowa aplikacja jest uruchamiana z przyciskami niedziałanymi

  2. Edytuj plik TouchViewController.cs i dodaj następujące dwie zmienne wystąpienia do klasy TouchViewController:

    #region Private Variables
    private bool imageHighlighted = false;
    private bool touchStartedInside;
    #endregion
    
  3. Zaimplementuj metodę TouchesBegan , jak pokazano w poniższym kodzie:

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

    Ta metoda działa, sprawdzając UITouch obiekt i jeśli istnieje, wykonaj jakąś akcję na podstawie miejsca wystąpienia dotyku:

    • Wewnątrz touchImage — wyświetla tekst Touches Began w etykiecie i zmienia obraz.
    • Wewnątrz DoubleTouchImage — zmień obraz wyświetlany, jeśli gest był dwukrotnie naciśnięciem.
    • Wewnątrz DragImage — ustaw flagę wskazującą, że dotyk został uruchomiony. Metoda TouchesMoved użyje tej flagi, aby określić, czy DragImage powinny być przenoszone po ekranie, jak zobaczymy w następnym kroku.

    Powyższy kod dotyczy tylko poszczególnych akcentów. Nadal nie ma żadnego zachowania, jeśli użytkownik porusza palcem na ekranie. Aby reagować na ruch, zaimplementuj TouchesMoved go, jak pokazano w poniższym kodzie:

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

    Ta metoda pobiera UITouch obiekt, a następnie sprawdza, gdzie wystąpił dotyk. Jeśli na ekranie wystąpił TouchImagedotyk, na ekranie zostanie wyświetlony tekst Touches Moved .

    Jeśli touchStartedInside to prawda, wiemy, że użytkownik ma palec i DragImage porusza się. Kod zostanie przeniesiony DragImage , gdy użytkownik porusza palcem po ekranie.

  4. Musimy poradzić sobie z przypadkiem, gdy użytkownik podnosi palcem z ekranu lub system iOS anuluje zdarzenie dotykowe. W tym celu zaimplementujemy i TouchesEndedTouchesCancelled , jak pokazano poniżej:

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

    Obie te metody zresetują flagę touchStartedInside na false. TouchesEnded zostanie również wyświetlony TouchesEnded na ekranie.

  5. Na tym etapie ekran Touch Samples jest gotowy. Zwróć uwagę, że ekran zmienia się podczas interakcji z poszczególnymi obrazami, jak pokazano na poniższym zrzucie ekranu:

    Ekran uruchamiania aplikacji

    Ekran po przeciągnięciu przycisku przez użytkownika

Przykłady rozpoznawania gestów

W poprzedniej sekcji pokazano, jak przeciągać obiekt wokół ekranu przy użyciu zdarzeń dotykowych. W tej sekcji usuniemy zdarzenia dotykowe i pokażemy, jak używać następujących funkcji rozpoznawania gestów:

  • Element UIPanGestureRecognizer do przeciągania obrazu na ekranie.
  • Odpowiedź UITapGestureRecognizer na podwójne naciśnięcia na ekranie.

Wykonaj następujące kroki, aby zaimplementować rozpoznawanie gestów:

  1. Edytuj plik GestureViewController.cs i dodaj następującą zmienną wystąpienia:

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

    Potrzebujemy tej zmiennej wystąpienia, aby śledzić poprzednią lokalizację obrazu. Rozpoznawanie gestów originalImageFrame przesuwania użyje wartości , aby obliczyć przesunięcie wymagane do ponownego wyrysowania obrazu na ekranie.

  2. Dodaj następującą metodę do kontrolera:

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

    Ten kod tworzy wystąpienie UIPanGestureRecognizer i dodaje je do widoku. Zwróć uwagę, że przypisujemy element docelowy do gestu w postaci metody HandleDrag — ta metoda jest podana w następnym kroku.

  3. Aby zaimplementować element HandleDrag, dodaj następujący kod do kontrolera:

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

    Powyższy kod najpierw sprawdzi stan rozpoznawania gestów, a następnie przeniesie obraz wokół ekranu. Dzięki temu kodowi kontroler może teraz obsługiwać przeciąganie jednego obrazu na ekranie.

  4. Dodaj element UITapGestureRecognizer , który spowoduje zmianę wyświetlanego obrazu w funkcji DoubleTouchImage. Dodaj następującą metodę do GestureViewController kontrolera:

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

    Ten kod jest bardzo podobny do kodu dla elementu UIPanGestureRecognizer , ale zamiast używać delegata dla obiektu docelowego, używamy elementu Action.

  5. Ostatnią rzeczą, którą musimy zrobić, jest zmodyfikowanie ViewDidLoad , aby wywołać właśnie dodane metody. Zmień element ViewDidLoad, aby przypominał następujący kod:

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

    Zwróć również uwagę, że inicjujemy wartość .originalImageFrame

  6. Uruchom aplikację i wchodzić w interakcje z tymi dwoma obrazami. Poniższy zrzut ekranu to jeden z przykładów tych interakcji:

    Ten zrzut ekranu przedstawia interakcję przeciągania

Niestandardowy aparat rozpoznawania gestów

W tej sekcji zastosujemy pojęcia z poprzednich sekcji, aby utworzyć niestandardowy aparat rozpoznawania gestów. Niestandardowy aparat rozpoznawania gestów będzie podklasami UIGestureRecognizeri rozpozna, gdy użytkownik rysuje "V" na ekranie, a następnie przełącza mapę bitową. Poniższy zrzut ekranu jest przykładem tego ekranu:

Aplikacja będzie rozpoznawana, gdy użytkownik rysuje maszynę wirtualną na ekranie

Wykonaj następujące kroki, aby utworzyć niestandardowy aparat rozpoznawania gestów:

  1. Dodaj nową klasę do projektu o nazwie CheckmarkGestureRecognizeri utwórz ją tak, jak w poniższym kodzie:

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

    Metoda Reset jest wywoływana, gdy State właściwość zmieni się na Recognized lub Ended. Jest to czas na zresetowanie dowolnego stanu wewnętrznego ustawionego w niestandardowym rozpoznawaniu gestów. Teraz klasa może zacząć od nowa przy następnej interakcji użytkownika z aplikacją i być gotowa do ponownej próby rozpoznania gestu.

  2. Teraz, gdy zdefiniowaliśmy niestandardowy aparat rozpoznawania gestów (CheckmarkGestureRecognizer) edytują plik CustomGestureViewController.cs i dodaliśmy następujące dwie zmienne wystąpienia:

    #region Private Variables
    private bool isChecked = false;
    private CheckmarkGestureRecognizer checkmarkGesture;
    #endregion
    
  3. Aby utworzyć wystąpienie i skonfigurować rozpoznawanie gestów, dodaj następującą metodę do kontrolera:

    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. Edytuj ViewDidLoad tak, aby wywołuje metodę WireUpCheckmarkGestureRecognizer, jak pokazano w poniższym fragmencie kodu:

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
    
        // Wire up the gesture recognizer
        WireUpCheckmarkGestureRecognizer();
    }
    
  5. Uruchom aplikację i spróbuj narysować "V" na ekranie. Powinna zostać wyświetlona zmiana obrazu, jak pokazano na poniższych zrzutach ekranu:

    Zaznaczony przycisk

    Przycisk nie jest zaznaczony

W powyższych trzech sekcjach przedstawiono różne sposoby reagowania na zdarzenia dotykowe w systemie iOS: używanie zdarzeń dotykowych, wbudowanych funkcji rozpoznawania gestów lub niestandardowego rozpoznawania gestów.