Rilevamento con più dita a tocco in Xamarin.iOS
Questo documento illustra come tenere traccia degli eventi di tocco da più dita
Ci sono momenti in cui un'applicazione multitocco deve tenere traccia delle singole dita mentre si spostano contemporaneamente sullo schermo. Un'applicazione tipica è un programma di pittura di dito. Si vuole che l'utente sia in grado di disegnare con un solo dito, ma anche di disegnare con più dita contemporaneamente. Poiché il programma elabora più eventi di tocco, deve distinguere tra queste dita.
Quando un dito tocca per la prima volta lo schermo, iOS crea un UITouch
oggetto per quel dito. Questo oggetto rimane lo stesso del dito che si muove sullo schermo e quindi solleva dallo schermo, a quel punto l'oggetto viene eliminato. Per tenere traccia delle dita, un programma deve evitare di archiviare direttamente questo UITouch
oggetto. Può invece usare la Handle
proprietà di tipo IntPtr
per identificare in modo univoco questi UITouch
oggetti.
Quasi sempre, un programma che tiene traccia delle singole dita mantiene un dizionario per il rilevamento del tocco. Per un programma iOS, la chiave del dizionario è il Handle
valore che identifica un dito specifico. Il valore del dizionario dipende dall'applicazione. Nel programma di esempio, ogni tratto del dito (dal tocco al rilascio) è associato a un oggetto che contiene tutte le informazioni necessarie per eseguire il rendering della linea disegnata con il dito. Il programma definisce una piccola FingerPaintPolyline
classe a questo scopo:
class FingerPaintPolyline
{
public FingerPaintPolyline()
{
Path = new CGPath();
}
public CGColor Color { set; get; }
public float StrokeWidth { set; get; }
public CGPath Path { private set; get; }
}
Ogni polilinea ha un colore, una larghezza del tratto e un oggetto grafico CGPath
iOS per accumulare ed eseguire il rendering di più punti della linea durante il disegno.
Tutto il resto del codice illustrato di seguito è contenuto in un UIView
derivato denominato FingerPaintCanvasView
. Tale classe mantiene un dizionario di oggetti di tipo FingerPaintPolyline
durante il tempo in cui vengono disegnati attivamente da una o più dita:
Dictionary<IntPtr, FingerPaintPolyline> inProgressPolylines = new Dictionary<IntPtr, FingerPaintPolyline>();
Questo dizionario consente alla visualizzazione di ottenere rapidamente le FingerPaintPolyline
informazioni associate a ogni dito in base alla Handle
proprietà dell'oggetto UITouch
.
La FingerPaintCanvasView
classe gestisce anche un List
oggetto per le polilinee completate:
List<FingerPaintPolyline> completedPolylines = new List<FingerPaintPolyline>();
Gli oggetti in questo List
oggetto si trovano nello stesso ordine in cui sono stati disegnati.
FingerPaintCanvasView
esegue l'override di cinque metodi definiti da View
:
Le varie Touches
sostituzioni accumulano i punti che costituiscono le polilinee.
L'override [Draw
] disegna le polilinee completate e quindi le polilinee in corso:
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);
}
}
}
Ognuna delle Touches
sostituzioni segnala potenzialmente le azioni di più dita, indicate da uno o più UITouch
oggetti archiviati nell'argomento touches
al metodo . Le TouchesBegan
sostituzioni eseguono il ciclo di questi oggetti. Per ogni UITouch
oggetto, il metodo crea e inizializza un nuovo FingerPaintPolyline
oggetto, inclusa l'archiviazione della posizione iniziale del dito ottenuto dal LocationInView
metodo . Questo FingerPaintPolyline
oggetto viene aggiunto al InProgressPolylines
dizionario usando la Handle
proprietà dell'oggetto UITouch
come chiave del dizionario:
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();
}
Il metodo termina chiamando SetNeedsDisplay
per generare una chiamata all'override Draw
e per aggiornare la schermata.
Quando il dito o le dita si spostano sullo schermo, ottiene View
più chiamate al suo TouchesMoved
override. Questo override esegue un ciclo simile negli UITouch
oggetti archiviati nell'argomento touches
e aggiunge la posizione corrente del dito al percorso grafico:
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();
}
L'insieme touches
contiene solo gli UITouch
oggetti per le dita spostate dall'ultima chiamata a TouchesBegan
o TouchesMoved
. Se sono necessari UITouch
oggetti corrispondenti a tutte le dita attualmente in contatto con lo schermo, tali informazioni sono disponibili tramite la AllTouches
proprietà dell'argomento UIEvent
al metodo .
L'override TouchesEnded
ha due processi. Deve aggiungere l'ultimo punto al percorso grafico e trasferire l'oggetto FingerPaintPolyline
dal inProgressPolylines
dizionario all'elenco 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();
}
L'override TouchesCancelled
viene gestito semplicemente abbandonando l'oggetto FingerPaintPolyline
nel dizionario:
public override void TouchesCancelled(NSSet touches, UIEvent evt)
{
base.TouchesCancelled(touches, evt);
foreach (UITouch touch in touches.Cast<UITouch>())
{
inProgressPolylines.Remove(touch.Handle);
}
SetNeedsDisplay();
}
Complessivamente, questa elaborazione consente al programma di esempio di tenere traccia delle singole dita e disegnare i risultati sullo schermo:
Ora hai visto come tenere traccia delle singole dita sullo schermo e distinguerle.