Návod: Používání dotykového ovládání v Xamarin.iOS
Tento názorný postup ukazuje, jak napsat kód, který reaguje na různé druhy dotykových událostí. Každý příklad je obsažený na samostatné obrazovce:
- Dotykové ukázky – jak reagovat na dotykové události.
- Ukázky rozpoznávání gest – jak používat integrované rozpoznávání gest.
- Ukázka vlastního rozpoznávání gest – jak vytvořit vlastní rozpoznávání gest.
Každá část obsahuje pokyny k napsání kódu úplně od začátku.
Podle následujících pokynů přidejte kód do scénáře a seznamte se s různými typy dotykových událostí dostupných v iOSu.
Ukázky dotykového ovládání
V této ukázce si ukážeme některá dotyková rozhraní API. Pokud chcete přidat kód potřebný k implementaci dotykových událostí, postupujte takto:
Otevřete Touch_Start projektu. Nejprve spusťte projekt, abyste měli jistotu, že je všechno v pořádku, a klepněte na tlačítko Vzorky dotykového ovládání. Měla by se zobrazit obrazovka podobná následující (i když žádná z tlačítek nebude fungovat):
Upravte soubor TouchViewController.cs a přidejte do třídy
TouchViewController
následující dvě proměnné instance:#region Private Variables private bool imageHighlighted = false; private bool touchStartedInside; #endregion
Implementujte metodu
TouchesBegan
, jak je znázorněno v následujícím kódu: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; } } }
Tato metoda funguje tak, že vyhledá
UITouch
objekt a pokud existuje, provede nějakou akci na základě místa, kde došlo k dotyku:- Uvnitř TouchImage – zobrazí text
Touches Began
v popisku a změní obrázek. - Uvnitř DoubleTouchImage – změňte obrázek zobrazený, pokud gesto bylo poklepání.
- Uvnitř DragImage – nastavte příznak označující, že se dotykové ovládání spustilo. Tato metoda
TouchesMoved
použije tento příznak k určení, jestliDragImage
se má pohybovat po obrazovce nebo ne, jak je vidět v dalším kroku.
Výše uvedený kód se zabývá pouze individuálními dotyky, neexistuje žádné chování, pokud uživatel posouvá prst na obrazovce. Pokud chcete reagovat na přesun, implementujte
TouchesMoved
ho, jak je znázorněno v následujícím kódu: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); } } }
Tato metoda získá
UITouch
objekt a pak zkontroluje, kde došlo k dotyku. Pokud k dotykovému ovládání došloTouchImage
, zobrazí se na obrazovce text Touches Moved (Přesunuto).Pokud
touchStartedInside
je pravda, pak víme, že uživatel má prst na ruceDragImage
a pohybuje se kolem. Kód se přesuneDragImage
, když uživatel posouvají prst po obrazovce.- Uvnitř TouchImage – zobrazí text
Musíme zpracovat případ, kdy uživatel zvedne prst z obrazovky nebo iOS zruší dotykovou událost. V tomto případě budeme implementovat
TouchesEnded
aTouchesCancelled
jak je znázorněno níže: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; }
Obě tyto metody resetují
touchStartedInside
příznak na false.TouchesEnded
zobrazí se takéTouchesEnded
na obrazovce.V tuto chvíli je obrazovka s dotykovými ukázkami hotová. Všimněte si, jak se obrazovka mění při interakci s jednotlivými obrázky, jak je znázorněno na následujícím snímku obrazovky:
Ukázky rozpoznávání gest
Předchozí část ukázala, jak přetáhnout objekt po obrazovce pomocí dotykových událostí. V této části se zbavíme dotykových událostí a ukážeme, jak používat následující rozpoznávání gest:
- Při
UIPanGestureRecognizer
přetahování obrázku po obrazovce. - Odpověď
UITapGestureRecognizer
na poklepáním na obrazovku
Při implementaci rozpoznávání gest postupujte takto:
Upravte soubor GestureViewController.cs a přidejte následující proměnnou instance:
#region Private Variables private bool imageHighlighted = false; private RectangleF originalImageFrame = RectangleF.Empty; #endregion
Tuto proměnnou instance potřebujeme, abychom mohli sledovat předchozí umístění image. Rozpoznávání gest posunu použije
originalImageFrame
hodnotu k výpočtu posunu potřebného k překreslení obrázku na obrazovce.Přidejte do kontroleru následující metodu:
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); }
Tento kód vytvoří
UIPanGestureRecognizer
instanci a přidá ji do zobrazení. Všimněte si, že k gestu ve formě metodyHandleDrag
přiřadíme cíl – tato metoda je k dispozici v dalším kroku.Pokud chcete implementovat HandleDrag, přidejte do kontroleru následující kód:
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; } }
Výše uvedený kód nejprve zkontroluje stav rozpoznávání gest a pak obrázek přesune po obrazovce. S tímto kódem teď může ovladač podporovat přetahování jednoho obrázku po obrazovce.
Přidejte obrázek
UITapGestureRecognizer
, který změní obrázek zobrazený v DoubleTouchImage. Přidejte do kontroleru následující metoduGestureViewController
: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); }
Tento kód je velmi podobný kódu pro kód,
UIPanGestureRecognizer
ale místo použití delegáta pro cíl, který používámeAction
.Poslední věcí, kterou musíme udělat, je upravit
ViewDidLoad
tak, aby volaly metody, které jsme právě přidali. Změňte ViewDidLoad tak, aby připomínal následující kód:public override void ViewDidLoad() { base.ViewDidLoad(); Title = "Gesture Recognizers"; // Save initial state originalImageFrame = DragImage.Frame; WireUpTapGestureRecognizer(); WireUpDragGestureRecognizer(); }
Všimněte si také, že inicializujeme hodnotu
originalImageFrame
.Spusťte aplikaci a komunikujte se dvěma imagemi. Následující snímek obrazovky je jedním z příkladů těchto interakcí:
Rozpoznávání vlastních gest
V této části použijeme koncepty z předchozích částí k vytvoření vlastního rozpoznávání gest. Rozpoznávání vlastních gest podtřídy UIGestureRecognizer
a rozpozná, když uživatel na obrazovce nakreslí "V" a pak přepne rastrový obrázek. Následující snímek obrazovky je příkladem této obrazovky:
Pokud chcete vytvořit vlastní rozpoznávání gest, postupujte takto:
Přidejte do projektu
CheckmarkGestureRecognizer
novou třídu a nastavte ji jako následující kód: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 je volána při
State
změně vlastnosti buďRecognized
neboEnded
. Toto je čas resetovat všechny interní stavy nastavené ve vlastním rozpoznávání gest. Teď může třída začít znovu začít znovu, až uživatel s aplikací komunikuje a bude připraven znovu zjistit gesto.Teď, když jsme definovali vlastní rozpoznávání gest (
CheckmarkGestureRecognizer
) upravte soubor CustomGestureViewController.cs a přidejte následující dvě proměnné instance:#region Private Variables private bool isChecked = false; private CheckmarkGestureRecognizer checkmarkGesture; #endregion
Pokud chcete vytvořit instanci a nakonfigurovat rozpoznávání gest, přidejte do kontroleru následující metodu:
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); }
Upravte
ViewDidLoad
tak, aby volalyWireUpCheckmarkGestureRecognizer
, jak je znázorněno v následujícím fragmentu kódu:public override void ViewDidLoad() { base.ViewDidLoad(); // Wire up the gesture recognizer WireUpCheckmarkGestureRecognizer(); }
Spusťte aplikaci a zkuste na obrazovce nakreslit "V". Měla by se zobrazit změna obrázku, jak je znázorněno na následujících snímcích obrazovky:
Výše uvedené tři části ukazují různé způsoby reakce na dotykové události v iOSu: použití dotykových událostí, integrovaných rozpoznávání gest nebo vlastního rozpoznávání gest.