Multitouch-Fingerverfolgung
In diesem Thema wird veranschaulicht, wie Touchereignisse von mehreren Fingern aus nachverfolgt werden.
Es gibt Situationen, in denen eine Multitouchanwendung einzelne Finger verfolgen muss, während sie sich gleichzeitig auf dem Bildschirm bewegen. Eine typische Anwendung ist ein Finger-Paint-Programm. Sie möchten, dass der Benutzer mit einem einzelnen Finger zeichnen kann, aber auch mit mehreren Fingern gleichzeitig zeichnen kann. Da Ihr Programm mehrere Touchereignisse verarbeitet, muss es unterscheiden, welche Ereignisse den einzelnen Fingern entsprechen. Android stellt zu diesem Zweck einen ID-Code bereit, aber das Abrufen und Behandeln dieses Codes kann ein wenig schwierig sein.
Für alle Ereignisse, die einem bestimmten Finger zugeordnet sind, bleibt der ID-Code gleich. Der ID-Code wird zugewiesen, wenn ein Finger den Bildschirm zum ersten Mal berührt, und wird ungültig, nachdem der Finger vom Bildschirm anhebt. Diese ID-Codes sind im Allgemeinen sehr kleine ganze Zahlen, und Android verwendet sie für spätere Touchereignisse.
Fast immer verwaltet ein Programm, das einzelne Finger verfolgt, ein Wörterbuch für die Touchverfolgung. Der Wörterbuchschlüssel ist der ID-Code, der einen bestimmten Finger identifiziert. Der Wert des Wörterbuchs hängt von der Anwendung ab. Im FingerPaint-Programm ist jeder Fingerstrich (von der Berührung bis zum Loslassen) einem Objekt zugeordnet, das alle Informationen enthält, die zum Rendern der mit diesem Finger gezeichneten Linie erforderlich sind. Das Programm definiert eine kleine FingerPaintPolyline
Klasse für diesen Zweck:
class FingerPaintPolyline
{
public FingerPaintPolyline()
{
Path = new Path();
}
public Color Color { set; get; }
public float StrokeWidth { set; get; }
public Path Path { private set; get; }
}
Jede Polylinie verfügt über eine Farbe, eine Strichbreite und ein Android-Grafikobjekt Path
, um beim Zeichnen mehrere Punkte der Linie zu sammeln und zu rendern.
Der Rest des unten gezeigten Codes ist in einer View
Derivat namens FingerPaintCanvasView
enthalten. Diese Klasse verwaltet ein Wörterbuch von Objekten vom Typ FingerPaintPolyline
, während sie aktiv von einem oder mehreren Fingern gezeichnet werden:
Dictionary<int, FingerPaintPolyline> inProgressPolylines = new Dictionary<int, FingerPaintPolyline>();
Mit diesem Wörterbuch kann die Ansicht schnell die Informationen abrufen, die FingerPaintPolyline
einem bestimmten Finger zugeordnet sind.
Die FingerPaintCanvasView
-Klasse verwaltet auch ein List
-Objekt für die abgeschlossenen Polylinien:
List<FingerPaintPolyline> completedPolylines = new List<FingerPaintPolyline>();
Die Objekte in diesem List
befinden sich in derselben Reihenfolge, in der sie gezeichnet wurden.
FingerPaintCanvasView
überschreibt zwei Methoden, die durch definiert sind View
:OnDraw
und OnTouchEvent
.
In ihrer OnDraw
Überschreibung zeichnet die Ansicht die abgeschlossenen Polylinien und zeichnet dann die laufenden Polylinien.
Die Außerkraftsetzung der OnTouchEvent
-Methode beginnt mit dem Abrufen eines pointerIndex
Werts aus der ActionIndex
-Eigenschaft. Dieser ActionIndex
Wert unterscheidet zwischen mehreren Fingern, ist aber nicht über mehrere Ereignisse hinweg konsistent. Aus diesem Grund verwenden Sie den pointerIndex
, um den Zeigerwert id
aus der GetPointerId
-Methode abzurufen. Diese ID ist für mehrere Ereignisse konsistent:
public override bool OnTouchEvent(MotionEvent args)
{
// Get the pointer index
int pointerIndex = args.ActionIndex;
// Get the id to identify a finger over the course of its progress
int id = args.GetPointerId(pointerIndex);
// Use ActionMasked here rather than Action to reduce the number of possibilities
switch (args.ActionMasked)
{
// ...
}
// Invalidate to update the view
Invalidate();
// Request continued touch input
return true;
}
Beachten Sie, dass die Außerkraftsetzung die ActionMasked
-Eigenschaft in der switch
-Anweisung anstelle der Action
-Eigenschaft verwendet. Dies ist der Grund:
Wenn Sie es mit Multitouch zu tun haben, hat die Action
Eigenschaft den Wert für MotionEventsAction.Down
den ersten Finger, um den Bildschirm zu berühren, und dann die Werte von Pointer2Down
und Pointer3Down
, da der zweite und dritte Finger den Bildschirm berühren. Wenn der vierte und fünfte Finger Kontakt herstellen, verfügt die Action
Eigenschaft über numerische Werte, die nicht einmal Membern der MotionEventsAction
Enumeration entsprechen! Sie müssen die Werte von Bitflags in den Werten untersuchen, um zu interpretieren, was sie bedeuten.
Wenn die Finger den Kontakt mit dem Bildschirm verlassen, weist die Action
Eigenschaft die Werte Pointer2Up
und Pointer3Up
für den zweiten und dritten Finger sowie Up
für den ersten Finger auf.
Die ActionMasked
-Eigenschaft nimmt weniger Werte an, da sie in Verbindung mit der ActionIndex
-Eigenschaft verwendet werden soll, um zwischen mehreren Fingern zu unterscheiden. Wenn die Finger den Bildschirm berühren, kann die -Eigenschaft nur für den ersten Finger und PointerDown
für nachfolgende Finger gleich seinMotionEventActions.Down
. Wenn die Finger den Bildschirm verlassen, ActionMasked
hat die Werte Pointer1Up
für die nachfolgenden Finger und Up
für den ersten Finger.
Bei Verwendung von ActionMasked
unterscheidet die ActionIndex
zwischen den nachfolgenden Fingern, um den Bildschirm zu berühren und zu verlassen, aber Sie müssen diesen Wert in der MotionEvent
Regel nicht verwenden, außer als Argument für andere Methoden im Objekt. Für Multitouch wird GetPointerId
eine der wichtigsten dieser Methoden im obigen Code aufgerufen. Diese Methode gibt einen Wert zurück, den Sie für einen Wörterbuchschlüssel verwenden können, um bestimmte Ereignisse den Fingern zuzuordnen.
Die OnTouchEvent
Überschreibung im FingerPaint-Programm verarbeitet die MotionEventActions.Down
Ereignisse und PointerDown
identisch, indem ein neues FingerPaintPolyline
Objekt erstellt und dem Wörterbuch hinzugefügt wird:
public override bool OnTouchEvent(MotionEvent args)
{
// Get the pointer index
int pointerIndex = args.ActionIndex;
// Get the id to identify a finger over the course of its progress
int id = args.GetPointerId(pointerIndex);
// Use ActionMasked here rather than Action to reduce the number of possibilities
switch (args.ActionMasked)
{
case MotionEventActions.Down:
case MotionEventActions.PointerDown:
// Create a Polyline, set the initial point, and store it
FingerPaintPolyline polyline = new FingerPaintPolyline
{
Color = StrokeColor,
StrokeWidth = StrokeWidth
};
polyline.Path.MoveTo(args.GetX(pointerIndex),
args.GetY(pointerIndex));
inProgressPolylines.Add(id, polyline);
break;
// ...
}
// ...
}
Beachten Sie, dass auch verwendet pointerIndex
wird, um die Position des Fingers in der Ansicht abzurufen. Alle Touchinformationen sind dem pointerIndex
Wert zugeordnet. Der id
identifiziert Finger eindeutig über mehrere Nachrichten hinweg, sodass dieser zum Erstellen des Wörterbucheintrags verwendet wird.
Ebenso behandelt die OnTouchEvent
Außerkraftsetzung die MotionEventActions.Up
und Pointer1Up
identisch, indem die fertige Polylinie in die completedPolylines
Auflistung übertragen wird, damit sie während der OnDraw
Außerkraftsetzung gezeichnet werden können. Der Code entfernt auch den id
Eintrag aus dem Wörterbuch:
public override bool OnTouchEvent(MotionEvent args)
{
// ...
switch (args.ActionMasked)
{
// ...
case MotionEventActions.Up:
case MotionEventActions.Pointer1Up:
inProgressPolylines[id].Path.LineTo(args.GetX(pointerIndex),
args.GetY(pointerIndex));
// Transfer the in-progress polyline to a completed polyline
completedPolylines.Add(inProgressPolylines[id]);
inProgressPolylines.Remove(id);
break;
case MotionEventActions.Cancel:
inProgressPolylines.Remove(id);
break;
}
// ...
}
Nun zum kniffligen Teil.
Zwischen den Down- und Up-Ereignissen gibt es in der Regel viele MotionEventActions.Move
Ereignisse. Diese werden in einem einzelnen Aufruf von OnTouchEvent
gebündelt, und sie müssen anders als die Down
Ereignisse und Up
behandelt werden. Der pointerIndex
zuvor aus der ActionIndex
-Eigenschaft abgerufene Wert muss ignoriert werden. Stattdessen muss die -Methode mehrere pointerIndex
Werte abrufen, indem sie zwischen 0 und der PointerCount
-Eigenschaft schleift, und dann eine id
für jeden dieser pointerIndex
Werte abrufen:
public override bool OnTouchEvent(MotionEvent args)
{
// ...
switch (args.ActionMasked)
{
// ...
case MotionEventActions.Move:
// Multiple Move events are bundled, so handle them differently
for (pointerIndex = 0; pointerIndex < args.PointerCount; pointerIndex++)
{
id = args.GetPointerId(pointerIndex);
inProgressPolylines[id].Path.LineTo(args.GetX(pointerIndex),
args.GetY(pointerIndex));
}
break;
// ...
}
// ...
}
Diese Art der Verarbeitung ermöglicht es dem FingerPaint-Programm , einzelne Finger nachzuverfolgen und die Ergebnisse auf dem Bildschirm zu zeichnen:
Sie haben nun gesehen, wie Sie einzelne Finger auf dem Bildschirm nachverfolgen und zwischen ihnen unterscheiden können.