Aracılığıyla paylaş


Çok Dokunmalı Parmak İzleme

Bu konu başlığında, dokunma olaylarını birden çok parmaktan izleme adımları gösterilmektedir

Çok dokunmalı bir uygulamanın ekranda aynı anda hareket ederken tek tek parmaklarını izlemesi gereken zamanlar vardır. Tipik bir uygulama parmak boyama programıdır. Kullanıcının tek parmakla çizim yapabilmesini ancak aynı anda birden çok parmakla çizim yapabilmesini istiyorsunuz. Programınız birden çok dokunma olayını işlerken, her bir parmakla ilgili olan olayları ayırt etmesi gerekir. Android bu amaçla bir kimlik kodu sağlar, ancak bu kodu almak ve işlemek biraz karmaşık olabilir.

Belirli bir parmakla ilişkili tüm olaylar için kimlik kodu aynı kalır. Kimlik kodu, bir parmak ekrana ilk kez dokunduğunda atanır ve parmak ekrandan kaldırıldıktan sonra geçersiz hale gelir. Bu kimlik kodları genellikle çok küçük tamsayılardır ve Android bunları daha sonraki dokunma olayları için yeniden kullanıyor.

Neredeyse her zaman, tek tek parmaklarını izleyen bir program, dokunma izleme için bir sözlük tutar. Sözlük anahtarı, belirli bir parmağı tanımlayan kimlik kodudur. Sözlük değeri uygulamaya bağlıdır. FingerPaint örneğinde, her parmak vuruşu (dokunmadan yayına) çizginin o parmakla çizilmesi için gerekli tüm bilgileri içeren bir nesneyle ilişkilendirilir. Program bu amaçla küçük FingerPaintPolyline bir sınıf tanımlar:

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

    public Color Color { set; get; }

    public float StrokeWidth { set; get; }

    public Path Path { private set; get; }
}

Her çok çizgi, çizilirken çizginin birden çok noktasında birikip işlemek için bir renk, vuruş genişliği ve bir Android grafik Path nesnesine sahiptir.

Aşağıda gösterilen kodun geri kalanı adlı FingerPaintCanvasViewbir View türev içinde yer alır. Bu sınıf, bir veya daha fazla parmakla etkin olarak çizildikleri süre boyunca türündeki FingerPaintPolyline nesnelerin bir sözlüğünü tutar:

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

Bu sözlük, görünümün belirli bir parmakla ilişkili bilgileri hızla almasını FingerPaintPolyline sağlar.

sınıfı, FingerPaintCanvasView tamamlanmış olan çok çizgili değerler için de bir List nesne tutar:

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

Bunun List içindeki nesneler, çizildiği sıradadır.

FingerPaintCanvasView tarafından Viewtanımlanan iki yöntemi geçersiz kılar: OnDraw ve OnTouchEvent. OnDraw Geçersiz kılmada, görünüm tamamlanmış çok çizgileri çizer ve sonra devam eden çok çizgilileri çizer.

yöntemi geçersiz OnTouchEvent kılma özelliğinden ActionIndex bir pointerIndex değer alarak başlar. Bu ActionIndex değer birden çok parmağı birbirinden ayırt eder, ancak birden çok olay arasında tutarlı değildir. Bu nedenle, yönteminden GetPointerId işaretçi id değerini almak için öğesini kullanırsınızpointerIndex. Bu kimlik birden çok olay arasında tutarlıdır :

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;
}

Geçersiz kılmanın özelliği yerine deyiminde switch özelliğini kullandığına ActionMaskedAction dikkat edin. Bunun nedeni şu şekildedir:

Çoklu dokunmayla ilgilenirken, özelliğin Action ilk parmağın MotionEventsAction.Down ekrana dokunması için bir değeri vardır ve ikinci ve üçüncü parmaklar da ekrana dokunduğundan ve Pointer3Down değerlerine Pointer2Down sahiptir. Dördüncü ve beşinci parmaklar iletişim kurarken, özelliğin Action numaralandırmanın MotionEventsAction üyelerine bile karşılık olmayan sayısal değerleri vardır! Anlamlarını yorumlamak için değerlerdeki bit bayraklarının değerlerini incelemeniz gerekir.

Benzer şekilde, parmaklar ekrana temas ettikçe, Action özellik ikinci ve Pointer3Up üçüncü parmaklar Pointer2Up için ve ilk parmak için değerlerine Up sahiptir.

ActionMasked özelliği, birden çok parmak arasında ayrım yapmak için özelliğiyle ActionIndex birlikte kullanılması amaçlandığı için daha az sayıda değer alır. Parmaklar ekrana dokunduğunda, özellik yalnızca ilk parmak ve PointerDown sonraki parmaklar için eşit MotionEventActions.Down olabilir. Parmaklar ekrandan ayrılırken, ActionMasked sonraki parmaklar Pointer1Up ve Up ilk parmak için değerleri vardır.

kullanırken ActionMasked, ActionIndex ekrana dokunmak ve ekrandan çıkmak için sonraki parmaklar arasında ayrım yapılır, ancak nesnedeki MotionEvent diğer yöntemlerin bağımsız değişkeni dışında genellikle bu değeri kullanmanız gerekmez. Çoklu dokunma için, bu yöntemlerden en önemlilerinden biri yukarıdaki kodda çağrılır GetPointerId . Bu yöntem, belirli olayları parmakla ilişkilendirmek için sözlük anahtarı için kullanabileceğiniz bir değer döndürür.

OnTouchEvent Örnekteki geçersiz kılma, yeni FingerPaintPolyline bir nesne oluşturup sözlüğe ekleyerek ve PointerDown olaylarını aynı şekilde işlerMotionEventActions.Down:

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;
        // ...
    }
    // ...        
}

görünümünün pointerIndex içinde parmağın konumunu elde etmek için de kullanıldığına dikkat edin. Tüm dokunma bilgileri değerle pointerIndex ilişkilendirilir. , id birden çok iletideki parmaklarını benzersiz olarak tanımlar, bu nedenle sözlük girdisini oluşturmak için kullanılır.

Benzer şekilde, OnTouchEvent geçersiz kılma, tamamlanmış çok çizgiliyiMotionEventActions.Up, geçersiz kılma sırasında çizilebilmeleri için koleksiyona completedPolylines aktararak ve Pointer1Up öğesini OnDraw de aynı şekilde işler. Kod ayrıca girdiyi id sözlükten kaldırır:

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;
    }
    // ...        
}

Şimdi de işin zor kısmı.

Aşağı ve yukarı olayları arasında genellikle birçok MotionEventActions.Move olay vardır. Bunlar tek bir çağrısında OnTouchEventpaketlenir ve ve Up olaylarından Down farklı şekilde işlenmelidir. pointerIndex Özelliğinden ActionIndex daha önce alınan değer yoksayılmalıdır. Bunun yerine, yöntemin 0 ile özelliği arasında döngü yaparak birden çok pointerIndex değer alması ve PointerCount ardından bu pointerIndex değerlerin her biri için bir id alması gerekir:

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;
        // ...
    }
    // ...        
}

Bu işlem türü, örneğin tek tek parmaklarını izlemesine ve sonuçları ekranda çizmesine olanak tanır:

FingerPaint örneğinden örnek ekran görüntüsü

Artık ekranda tek tek parmaklarını nasıl izleyebilebileceğinizi ve aralarında nasıl ayrım yapabileceğinizi gördünüz.