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();
}
集合 touches
只 UITouch
包含自上次呼叫 TouchesBegan
或 TouchesMoved
之後已移動之手指的物件。 如果您曾經需要 UITouch
對應至 目前與螢幕接觸的所有 手指的物件,該資訊可透過 AllTouches
自變數的 UIEvent
屬性提供給 方法。
覆 TouchesEnded
寫有兩個作業。 它必須將最後一個點新增至圖形路徑,並將物件從inProgressPolylines
字典傳送FingerPaintPolyline
至completedPolylines
清單:
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();
}
此處理完全允許範例程式追蹤個別手指,並在畫面上繪製結果:
您現在已瞭解如何追蹤螢幕上的個別手指,並區分它們。