Multitouchfingerverfolgung
In diesem Thema wird das Nachverfolgen von Touchereignissen von mehreren Fingern veranschaulicht.
Es gibt Situationen, in denen eine Multitouchanwendung einzelne Finger nachverfolgen muss, während sie gleichzeitig auf dem Bildschirm bewegt werden. Eine typische Anwendung ist ein Fingerfarbenprogramm. Sie möchten, dass der Benutzer mit einem Finger zeichnen kann, aber auch mit mehreren Fingern gleichzeitig zeichnen kann. Wenn Ihr Programm mehrere Touchereignisse verarbeitet, muss unterschieden werden, welche Ereignisse jedem Finger entsprechen. Android stellt einen ID-Code für diesen Zweck zur Hand, aber das Abrufen und Behandeln dieses Codes kann ein wenig schwierig sein.
Für alle Ereignisse, die einem bestimmten Finger zugeordnet sind, wird der ID-Code erneut Standard identisch. Der ID-Code wird zugewiesen, wenn ein Finger zuerst den Bildschirm berührt und nach dem Aufheben des Fingers vom Bildschirm ungültig wird. Diese ID-Codes sind im Allgemeinen sehr kleine ganze Zahlen, und Android verwendet sie für spätere Touchereignisse wieder.
Fast immer, ein Programm, das einzelne Finger verfolgt, Standard ein Wörterbuch zur Touchverfolgung enthält. Der Wörterbuchschlüssel ist der ID-Code, der einen bestimmten Finger identifiziert. Der Wörterbuchwert hängt von der Anwendung ab. Im FingerPaint-Beispiel ist jeder Fingerstrich (von Der Fingereingabe bis zur Freigabe) einem Objekt zugeordnet, das alle erforderlichen Informationen enthält, um die mit dem Finger gezeichnete Linie zu rendern. Das Programm definiert für diesen Zweck eine kleine FingerPaintPolyline
Klasse:
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 mehrere Punkte der Linie zu sammeln und zu rendern, während sie gezeichnet wird.
Der Re Standard der des unten gezeigten Codes ist in einem View
Abgeleiteten namens FingerPaintCanvasView
enthalten. Diese Klasse Standard enthält ein Wörterbuch von Objekten vom Typ während FingerPaintPolyline
der Zeit, in der 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 FingerPaintPolyline
mit einem bestimmten Finger verbundenen Informationen abrufen.
Die FingerPaintCanvasView
Klasse Standard enthält auch ein List
Objekt für die polylines, die abgeschlossen wurden:
List<FingerPaintPolyline> completedPolylines = new List<FingerPaintPolyline>();
Die Objekte in dieser List
Reihenfolge befinden sich in derselben Reihenfolge, in der sie gezeichnet wurden.
FingerPaintCanvasView
überschreibt zwei methoden, die durch View
: OnDraw
und OnTouchEvent
.
In seiner OnDraw
Überschreibung zeichnet die Ansicht die fertigen 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 für mehrere Ereignisse konsistent. Aus diesem Grund verwenden Sie den pointerIndex
Zeigerwert id
aus der GetPointerId
Methode. 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 mit Multitouch arbeiten, hat die Action
Eigenschaft einen Wert für MotionEventsAction.Down
den ersten Finger, um den Bildschirm zu berühren, und dann werte von Pointer2Down
und Pointer3Down
als zweiter und dritter Finger auch den Bildschirm. Wenn der vierte und fünfte Finger Kontakt herstellen, weist die Action
Eigenschaft numerische Werte auf, die nicht einmal Mitgliedern der MotionEventsAction
Enumeration entsprechen! Sie müssen die Werte von Bitkennzeichnungen in den Werten untersuchen, um die Bedeutung zu interpretieren.
Ebenso wie die Finger den Kontakt mit dem Bildschirm verlassen, weist die Action
Eigenschaft Werte für Pointer2Up
Pointer3Up
die zweiten und dritten Finger und Up
für den ersten Finger auf.
Die ActionMasked
Eigenschaft verwendet weniger Werte, da sie zusammen mit der ActionIndex
Eigenschaft verwendet werden soll, um zwischen mehreren Fingern zu unterscheiden. Wenn Finger den Bildschirm berühren, kann die Eigenschaft nur für den ersten Finger und PointerDown
für nachfolgende Finger gleich MotionEventActions.Down
sein. Wenn die Finger den Bildschirm verlassen, ActionMasked
weist die Werte Pointer1Up
für die nachfolgenden Finger und Up
für den ersten Finger auf.
Bei Verwendung ActionMasked
wird zwischen ActionIndex
den nachfolgenden Fingern unterschieden, um den Bildschirm zu berühren und den Bildschirm zu verlassen. In der Regel müssen Sie diesen Wert jedoch nicht verwenden, außer als Argument für andere Methoden im MotionEvent
Objekt. Bei 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 bestimmten Ereignissen Fingern zuzuordnen.
Die OnTouchEvent
Außerkraftsetzung im Beispiel verarbeitet die MotionEventActions.Down
Ereignisse und PointerDown
Ereignisse 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 die pointerIndex
Position des Fingers in der Ansicht auch verwendet wird. Alle Fingereingabeinformationen sind dem pointerIndex
Wert zugeordnet. Die id
Finger werden eindeutig über mehrere Nachrichten hinweg identifiziert, sodass sie zum Erstellen des Wörterbucheintrags verwendet werden.
Ebenso behandelt die OnTouchEvent
Überschreibung auch die MotionEventActions.Up
und Pointer1Up
identische Überschreibung, indem die abgeschlossene Polylinie in die completedPolylines
Auflistung übertragen wird, sodass sie während der OnDraw
Überschreibung gezeichnet werden können. Der Code entfernt außerdem 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;
}
// ...
}
Jetzt für den schwierigen Teil.
Zwischen den Down- und Up-Ereignissen gibt es in der Regel viele MotionEventActions.Move
Ereignisse. Diese werden in einem einzigen Aufruf OnTouchEvent
gebündelt und müssen anders behandelt werden als die Down
Ereignisse Up
. 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 durchlaufen und dann einen 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 von Verarbeitung ermöglicht es dem Beispiel, 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.