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:
- Próbki dotyku — sposób reagowania na zdarzenia dotykowe.
- Przykłady rozpoznawania gestów — jak używać wbudowanych funkcji rozpoznawania gestów.
- Przykład niestandardowego rozpoznawania gestów — sposób tworzenia niestandardowego rozpoznawania gestów.
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:
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ć):
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
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ć, czyDragImage
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łTouchImage
dotyk, na ekranie zostanie wyświetlony tekst Touches Moved .Jeśli
touchStartedInside
to prawda, wiemy, że użytkownik ma palec iDragImage
porusza się. Kod zostanie przeniesionyDragImage
, gdy użytkownik porusza palcem po ekranie.- Wewnątrz touchImage — wyświetla tekst
Musimy poradzić sobie z przypadkiem, gdy użytkownik podnosi palcem z ekranu lub system iOS anuluje zdarzenie dotykowe. W tym celu zaimplementujemy i
TouchesEnded
TouchesCancelled
, 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świetlonyTouchesEnded
na ekranie.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:
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:
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.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 metodyHandleDrag
— ta metoda jest podana w następnym kroku.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.
Dodaj element
UITapGestureRecognizer
, który spowoduje zmianę wyświetlanego obrazu w funkcji DoubleTouchImage. Dodaj następującą metodę doGestureViewController
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 elementuAction
.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
Uruchom aplikację i wchodzić w interakcje z tymi dwoma obrazami. Poniższy zrzut ekranu to jeden z przykładów tych interakcji:
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 UIGestureRecognizer
i rozpozna, gdy użytkownik rysuje "V" na ekranie, a następnie przełącza mapę bitową. Poniższy zrzut ekranu jest przykładem tego ekranu:
Wykonaj następujące kroki, aby utworzyć niestandardowy aparat rozpoznawania gestów:
Dodaj nową klasę do projektu o nazwie
CheckmarkGestureRecognizer
i 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ę naRecognized
lubEnded
. 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.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
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); }
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(); }
Uruchom aplikację i spróbuj narysować "V" na ekranie. Powinna zostać wyświetlona zmiana obrazu, jak pokazano na poniższych zrzutach ekranu:
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.