共用方式為


Xamarin.iOS 中的多點觸控手指追蹤

本文件示範如何追蹤多指的觸控事件

有時,多觸控應用程式需要追蹤個別手指,因為它們同時在螢幕上移動。 一個典型的應用程式是手指繪製程式。 您希望用戶能夠使用單指繪製,但也想要一次使用多根手指繪製。 當您的程式處理多個觸控事件時,它必須區分這些手指。

當手指第一次觸碰螢幕時,iOS 會 UITouch 建立該手指的物件。 此物件會維持與手指在畫面上移動一樣,然後從畫面上抬起,此時會處置物件。 為了追蹤手指,程序應該避免直接儲存此 UITouch 物件。 相反地,它可以使用 Handle 類型的 IntPtr 屬性來唯一識別這些 UITouch 物件。

幾乎一律是追蹤個別手指的程式會維護觸控追蹤的字典。 針對 iOS 程式,字典索引鍵是 Handle 識別特定手指的值。 字典值取決於應用程式。 在範例程式中,每個手指筆劃(從觸控到釋放)都與對象相關聯,其中包含使用該手指繪製線條所需的所有資訊。 程式會為此目的定義小型 FingerPaintPolyline 類別:

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

    public CGColor Color { set; get; }

    public float StrokeWidth { set; get; }

    public CGPath Path { private set; get; }
}

每個聚合線條都有色彩、筆劃寬度和iOS圖形 CGPath 物件,以在繪製線條時累積和轉譯多點。

下面顯示的所有其餘程序代碼都包含在名為 FingerPaintCanvasView的衍生工具中UIView。 該類別會在一或多個手指主動繪製物件時,維護型 FingerPaintPolyline 別物件的字典:

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

此字典可讓檢視根據 Handle 對象的 屬性UITouch,快速取得FingerPaintPolyline與每個手指相關聯的資訊。

類別 FingerPaintCanvasView 也會針對已完成的聚合線條維護 List 物件:

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

這個 List 中的物件順序與繪製的順序相同。

FingerPaintCanvasView 會覆寫 由 定義的 View五個方法:

各種 Touches 覆寫會累積構成聚合線條的點。

[Draw] 覆寫會繪製已完成的聚合線條,然後繪製進行中的聚合線條:

public override void Draw(CGRect rect)
{
    base.Draw(rect);

    using (CGContext context = UIGraphics.GetCurrentContext())
    {
        // Stroke settings
        context.SetLineCap(CGLineCap.Round);
        context.SetLineJoin(CGLineJoin.Round);

        // Draw the completed polylines
        foreach (FingerPaintPolyline polyline in completedPolylines)
        {
            context.SetStrokeColor(polyline.Color);
            context.SetLineWidth(polyline.StrokeWidth);
            context.AddPath(polyline.Path);
            context.DrawPath(CGPathDrawingMode.Stroke);
        }

        // Draw the in-progress polylines
        foreach (FingerPaintPolyline polyline in inProgressPolylines.Values)
        {
            context.SetStrokeColor(polyline.Color);
            context.SetLineWidth(polyline.StrokeWidth);
            context.AddPath(polyline.Path);
            context.DrawPath(CGPathDrawingMode.Stroke);
        }
    }
}

Touches每個覆寫都可能會報告多個手指的動作,由儲存在 自變數中的touches一個或多個UITouch物件向方法表示。 覆 TouchesBegan 寫會循環這些物件。 針對每個 UITouch 物件,方法會建立並初始化新的 FingerPaintPolyline 物件,包括儲存從 LocationInView 方法取得之手指的初始位置。 此FingerPaintPolyline物件會使用 Handle 物件的 屬性UITouch做為字典索引鍵,新增至InProgressPolylines字典:

public override void TouchesBegan(NSSet touches, UIEvent evt)
{
    base.TouchesBegan(touches, evt);

    foreach (UITouch touch in touches.Cast<UITouch>())
    {
        // Create a FingerPaintPolyline, set the initial point, and store it
        FingerPaintPolyline polyline = new FingerPaintPolyline
        {
            Color = StrokeColor,
            StrokeWidth = StrokeWidth,
        };

        polyline.Path.MoveToPoint(touch.LocationInView(this));
        inProgressPolylines.Add(touch.Handle, polyline);
    }
    SetNeedsDisplay();
}

方法最後是呼叫 SetNeedsDisplay 以產生覆寫的 Draw 呼叫並更新畫面。

當手指或手指在螢幕上移動時, View 會取得其 TouchesMoved 覆寫的多個呼叫。 此覆寫同樣會迴圈查看 UITouch 儲存在 自變數中的 touches 物件,並將手指的目前位置新增至圖形路徑:

public override void TouchesMoved(NSSet touches, UIEvent evt)
{
    base.TouchesMoved(touches, evt);

    foreach (UITouch touch in touches.Cast<UITouch>())
    {
        // Add point to path
        inProgressPolylines[touch.Handle].Path.AddLineToPoint(touch.LocationInView(this));
    }
    SetNeedsDisplay();
}

集合 touchesUITouch 包含自上次呼叫 TouchesBeganTouchesMoved之後已移動之手指的物件。 如果您曾經需要 UITouch 對應至 目前與螢幕接觸的所有 手指的物件,該資訊可透過 AllTouches 自變數的 UIEvent 屬性提供給 方法。

TouchesEnded 寫有兩個作業。 它必須將最後一個點新增至圖形路徑,並將物件從inProgressPolylines字典傳送FingerPaintPolylinecompletedPolylines清單:

public override void TouchesEnded(NSSet touches, UIEvent evt)
{
    base.TouchesEnded(touches, evt);

    foreach (UITouch touch in touches.Cast<UITouch>())
    {
        // Get polyline from dictionary and remove it from dictionary
        FingerPaintPolyline polyline = inProgressPolylines[touch.Handle];
        inProgressPolylines.Remove(touch.Handle);

        // Add final point to path and save with completed polylines
        polyline.Path.AddLineToPoint(touch.LocationInView(this));
        completedPolylines.Add(polyline);
    }
    SetNeedsDisplay();
}

TouchesCancelled 寫是藉由放棄 FingerPaintPolyline 字典中的 對象來處理:

public override void TouchesCancelled(NSSet touches, UIEvent evt)
{
    base.TouchesCancelled(touches, evt);

    foreach (UITouch touch in touches.Cast<UITouch>())
    {
        inProgressPolylines.Remove(touch.Handle);
    }
    SetNeedsDisplay();
}

此處理完全允許範例程式追蹤個別手指,並在畫面上繪製結果:

追蹤個別手指並在畫面上繪製結果

您現在已瞭解如何追蹤螢幕上的個別手指,並區分它們。