Udostępnij za pośrednictwem


Śledzenie palcem wielodotykowym na platformie Xamarin.iOS

W tym dokumencie pokazano, jak śledzić zdarzenia dotykowe z wielu palców

Czasami aplikacja wielodotykowa musi śledzić poszczególne palce, gdy poruszają się jednocześnie na ekranie. Jedną z typowych aplikacji jest program malowania palcami. Chcesz, aby użytkownik mógł rysować za pomocą pojedynczego palca, ale także rysować z wieloma palcami jednocześnie. Ponieważ program przetwarza wiele zdarzeń dotykowych, musi odróżnić te palce.

Gdy palec po raz pierwszy dotyka ekranu, system iOS tworzy UITouch obiekt dla tego palca. Ten obiekt pozostaje taki sam, jak palec porusza się na ekranie, a następnie podnosi się z ekranu, w którym momencie obiekt jest usuwany. Aby śledzić palce, program powinien unikać bezpośredniego przechowywania tego UITouch obiektu. Zamiast tego może użyć Handle właściwości typu IntPtr , aby jednoznacznie zidentyfikować te UITouch obiekty.

Prawie zawsze, program, który śledzi poszczególne palce utrzymuje słownik do śledzenia dotyku. W przypadku programu dla systemu iOS klucz słownika Handle jest wartością identyfikującą konkretny palec. Wartość słownika zależy od aplikacji. W przykładowym programie każdy pociągnięcie palca (od dotyku do zwolnienia) jest skojarzone z obiektem zawierającym wszystkie informacje niezbędne do renderowania linii rysowanej palcem. Program definiuje małą FingerPaintPolyline klasę w tym celu:

class FingerPaintPolyline
{
    public FingerPaintPolyline()
    {
        Path = new CGPath();
    }

    public CGColor Color { set; get; }

    public float StrokeWidth { set; get; }

    public CGPath Path { private set; get; }
}

Każda wielowierszowa ma kolor, szerokość pociągnięcia i obiekt graficzny CGPath systemu iOS do gromadzenia i renderowania wielu punktów linii podczas rysowania.

Cała reszta kodu pokazanego poniżej znajduje się w pochodnej UIView nazwie FingerPaintCanvasView. Ta klasa utrzymuje słownik obiektów typu FingerPaintPolyline w czasie, gdy są aktywnie rysowane przez co najmniej jeden palec:

Dictionary<IntPtr, FingerPaintPolyline> inProgressPolylines = new Dictionary<IntPtr, FingerPaintPolyline>();

Ten słownik umożliwia szybkie uzyskanie FingerPaintPolyline informacji skojarzonych z każdym palcem na Handle podstawie właściwości UITouch obiektu.

Klasa FingerPaintCanvasView obsługuje List również obiekt dla linii polilinii, które zostały ukończone:

List<FingerPaintPolyline> completedPolylines = new List<FingerPaintPolyline>();

Obiekty w tej List kolejności znajdują się w tej samej kolejności, w której zostały narysowane.

FingerPaintCanvasView zastępuje pięć metod zdefiniowanych przez Viewmetodę :

Różne Touches przesłonięcia gromadzą punkty, które składają się na linie wielokątne.

Przesłonięcia [Draw] rysują ukończone linie wieloliniowe, a następnie linie wieloliniowe w toku:

public override void Draw(CGRect rect)
{
    base.Draw(rect);

    using (CGContext context = UIGraphics.GetCurrentContext())
    {
        // Stroke settings
        context.SetLineCap(CGLineCap.Round);
        context.SetLineJoin(CGLineJoin.Round);

        // Draw the completed polylines
        foreach (FingerPaintPolyline polyline in completedPolylines)
        {
            context.SetStrokeColor(polyline.Color);
            context.SetLineWidth(polyline.StrokeWidth);
            context.AddPath(polyline.Path);
            context.DrawPath(CGPathDrawingMode.Stroke);
        }

        // Draw the in-progress polylines
        foreach (FingerPaintPolyline polyline in inProgressPolylines.Values)
        {
            context.SetStrokeColor(polyline.Color);
            context.SetLineWidth(polyline.StrokeWidth);
            context.AddPath(polyline.Path);
            context.DrawPath(CGPathDrawingMode.Stroke);
        }
    }
}

Każde z Touches przesłonięć potencjalnie zgłasza akcje wielu palców, wskazywane przez co najmniej jeden UITouch obiekt przechowywany w argumencie touches metody . Przesłonięcia TouchesBegan przechodzą przez te obiekty. Dla każdego UITouch obiektu metoda tworzy i inicjuje nowy FingerPaintPolyline obiekt, w tym przechowywanie początkowej lokalizacji palca uzyskanego LocationInView z metody . Ten FingerPaintPolyline obiekt jest dodawany do InProgressPolylines słownika przy użyciu Handle właściwości UITouch obiektu jako klucza słownika:

public override void TouchesBegan(NSSet touches, UIEvent evt)
{
    base.TouchesBegan(touches, evt);

    foreach (UITouch touch in touches.Cast<UITouch>())
    {
        // Create a FingerPaintPolyline, set the initial point, and store it
        FingerPaintPolyline polyline = new FingerPaintPolyline
        {
            Color = StrokeColor,
            StrokeWidth = StrokeWidth,
        };

        polyline.Path.MoveToPoint(touch.LocationInView(this));
        inProgressPolylines.Add(touch.Handle, polyline);
    }
    SetNeedsDisplay();
}

Metoda kończy się wywołaniem SetNeedsDisplay wywołania przesłonięcia Draw i zaktualizowania ekranu.

Gdy palec lub palce poruszają się na ekranie, View otrzymuje wiele wywołań do jego TouchesMoved przesłonięcia. To przesłonięcie podobnie przechodzi przez UITouch obiekty przechowywane w argumencie touches i dodaje bieżącą lokalizację palca do ścieżki grafiki:

public override void TouchesMoved(NSSet touches, UIEvent evt)
{
    base.TouchesMoved(touches, evt);

    foreach (UITouch touch in touches.Cast<UITouch>())
    {
        // Add point to path
        inProgressPolylines[touch.Handle].Path.AddLineToPoint(touch.LocationInView(this));
    }
    SetNeedsDisplay();
}

Kolekcja touches zawiera tylko te UITouch obiekty dla palców, które zostały przeniesione od ostatniego wywołania do TouchesBegan lub TouchesMoved. Jeśli kiedykolwiek potrzebujesz UITouch obiektów odpowiadających wszystkim palcam, które są obecnie w kontakcie z ekranem, informacje te są dostępne za pośrednictwem AllTouches właściwości argumentu UIEvent do metody .

Przesłonięcia TouchesEnded mają dwa zadania. Musi dodać ostatni punkt do ścieżki grafiki i przenieść FingerPaintPolyline obiekt ze inProgressPolylines słownika completedPolylines do listy:

public override void TouchesEnded(NSSet touches, UIEvent evt)
{
    base.TouchesEnded(touches, evt);

    foreach (UITouch touch in touches.Cast<UITouch>())
    {
        // Get polyline from dictionary and remove it from dictionary
        FingerPaintPolyline polyline = inProgressPolylines[touch.Handle];
        inProgressPolylines.Remove(touch.Handle);

        // Add final point to path and save with completed polylines
        polyline.Path.AddLineToPoint(touch.LocationInView(this));
        completedPolylines.Add(polyline);
    }
    SetNeedsDisplay();
}

Przesłonięcia TouchesCancelled są obsługiwane przez po prostu porzucenie FingerPaintPolyline obiektu w słowniku:

public override void TouchesCancelled(NSSet touches, UIEvent evt)
{
    base.TouchesCancelled(touches, evt);

    foreach (UITouch touch in touches.Cast<UITouch>())
    {
        inProgressPolylines.Remove(touch.Handle);
    }
    SetNeedsDisplay();
}

W sumie to przetwarzanie umożliwia przykładowemu programowi śledzenie poszczególnych palców i rysowanie wyników na ekranie:

Śledzenie poszczególnych palców i rysowanie wyników na ekranie

Wiesz już, jak można śledzić poszczególne palce na ekranie i rozróżniać je.