Sdílet prostřednictvím


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 Pointer2DownPointer3Down 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í ActionMaskedse 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í OnTouchEventa 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:

Příklad snímku obrazovky prstu Malování příklad

Teď jste viděli, jak můžete sledovat jednotlivé prsty na obrazovce a rozlišovat mezi nimi.