Sledování vícedotykového prstu
Toto téma ukazuje, jak sledovat dotykové události z více prstů.
Existují časy, kdy aplikace pro vícedotykové ovládání potřebuje sledovat jednotlivé prsty, když se pohybují současně na obrazovce. Jednou z typických aplikací je program malování prstem. Chcete, aby uživatel mohl kreslit jedním prstem, ale také kreslit více prsty najednou. Když program zpracovává více dotykových událostí, musí rozlišovat, které události odpovídají jednotlivým prstům. Android poskytuje kód ID pro tento účel, ale získání a zpracování tohoto kódu může být trochu složité.
Pro všechny události přidružené k určitému prstu zůstane kód ID stejný. Kód ID se přiřadí, když se prst poprvé dotkne obrazovky a po zvednutí prstu z obrazovky se stane neplatným. Tyto kódy ID jsou obecně velmi malá celá čísla a Android je opakovaně používá pro pozdější události dotykového ovládání.
Téměř vždy program, který sleduje jednotlivé prsty, udržuje slovník pro sledování dotykového ovládání. Klíč slovníku je kód ID, který identifikuje konkrétní prst. Hodnota slovníku závisí na aplikaci. V ukázce Prst Malování je každý tah prstem (od dotykového do uvolnění) přidružený k objektu, který obsahuje všechny informace potřebné k vykreslení čáry kreslené tímto prstem. Program definuje malou FingerPaintPolyline
třídu pro tento účel:
class FingerPaintPolyline
{
public FingerPaintPolyline()
{
Path = new Path();
}
public Color Color { set; get; }
public float StrokeWidth { set; get; }
public Path Path { private set; get; }
}
Každá křivka má barvu, šířku tahu a grafický Path
objekt Androidu, který se má nashromáždět a vykreslit více bodů čáry při jeho vykreslení.
Zbývající část níže uvedeného kódu je obsažena v derivátu View
s názvem FingerPaintCanvasView
. Tato třída udržuje slovník objektů typu FingerPaintPolyline
během doby, kdy jsou aktivně kresleny jedním nebo více prsty:
Dictionary<int, FingerPaintPolyline> inProgressPolylines = new Dictionary<int, FingerPaintPolyline>();
Tento slovník umožňuje zobrazení rychle získat FingerPaintPolyline
informace přidružené k určitému prstu.
Třída FingerPaintCanvasView
také udržuje List
objekt pro křivky, které byly dokončeny:
List<FingerPaintPolyline> completedPolylines = new List<FingerPaintPolyline>();
Objekty v tomto List
pořadí jsou ve stejném pořadí, v jakém byly nakresleny.
FingerPaintCanvasView
přepisuje dvě metody definované View
: OnDraw
a OnTouchEvent
.
V jeho OnDraw
přepsání zobrazení nakreslí dokončené čáry a pak nakreslí probíhající čáry.
Přepsání OnTouchEvent
metody začíná získáním pointerIndex
hodnoty z ActionIndex
vlastnosti. Tato ActionIndex
hodnota rozlišuje mezi více prsty, ale není konzistentní napříč více událostmi. Z tohoto důvodu použijete pointerIndex
k získání hodnoty ukazatele id
z GetPointerId
metody. Toto ID je konzistentní napříč několika událostmi:
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;
}
Všimněte si, že přepsání používá ActionMasked
vlastnost v switch
příkazu místo Action
vlastnosti. Tady je důvod:
Při práci s vícedotykovým ovládáním Action
má vlastnost hodnotu MotionEventsAction.Down
prvního prstu, která se dotkne obrazovky, a pak hodnoty a Pointer2Down
Pointer3Down
hodnoty druhé a třetí prsty se také dotknou obrazovky. Jako čtvrtý a pátý prst kontakt má Action
vlastnost číselné hodnoty, které ani neodpovídají členům výčtu MotionEventsAction
! Je potřeba prozkoumat hodnoty bitových příznaků v hodnotách, abyste mohli interpretovat, co znamenají.
Podobně jako prsty opustí kontakt s obrazovkou, Action
vlastnost má hodnoty Pointer2Up
druhého Pointer3Up
a třetího prstu a Up
pro první prst.
Vlastnost ActionMasked
přebírá méně hodnot, protože má být použita ve spojení s ActionIndex
vlastností k rozlišení mezi více prsty. Když prsty dotknou obrazovku, vlastnost se může rovnat MotionEventActions.Down
pouze prvnímu prstu a PointerDown
následným prstům. Když prsty opouštějí obrazovku, ActionMasked
mají hodnoty Pointer1Up
pro následné prsty a Up
první prst.
Při použití ActionMasked
se ActionIndex
rozlišují mezi následujícími prsty k dotyku a opuštění obrazovky, ale obvykle tuto hodnotu nemusíte používat s výjimkou argumentu pro jiné metody v objektu MotionEvent
. Pro vícedotykový, jeden z nejdůležitějších těchto metod je GetPointerId
volána v kódu výše. Tato metoda vrátí hodnotu, kterou můžete použít pro klíč slovníku pro přidružení konkrétních událostí k prstům.
Přepsání OnTouchEvent
v ukázce zpracovává MotionEventActions.Down
události stejně PointerDown
vytvořením nového FingerPaintPolyline
objektu a jeho přidáním do slovníku:
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;
// ...
}
// ...
}
Všimněte si, že pointerIndex
se používá také k získání pozice prstu v zobrazení. Všechny dotykové informace jsou přidružené k hodnotě pointerIndex
. Jedinečně id
identifikuje prsty napříč více zprávami, takže se používá k vytvoření položky slovníku.
Podobně přepsání také zpracovává MotionEventActions.Up
a identicky tím, OnTouchEvent
že přenese dokončenou křivku do completedPolylines
kolekce, aby je bylo možné kreslit během OnDraw
přepsáníPointer1Up
. Kód také odebere id
položku ze slovníku:
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;
}
// ...
}
Teď pro tu složitou část.
Mezi událostmi dolů a nahoru obecně existuje mnoho MotionEventActions.Move
událostí. Ty jsou spojeny do jednoho volání OnTouchEvent
a musí se zpracovávat jinak než Down
události.Up
Hodnota pointerIndex
získaná dříve z ActionIndex
vlastnosti musí být ignorována. Místo toho musí metoda získat více pointerIndex
hodnot smyčkou mezi 0 a PointerCount
vlastností a pak získat id
pro každou z těchto pointerIndex
hodnot:
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;
// ...
}
// ...
}
Tento typ zpracování umožňuje vzorku sledovat jednotlivé prsty a kreslit výsledky na obrazovce:
Teď jste viděli, jak můžete sledovat jednotlivé prsty na obrazovce a rozlišovat mezi nimi.