Rastreamento de dedos multitoque no Xamarin.iOS
Este documento demonstra como rastrear eventos de toque de vários dedos
Há momentos em que um aplicativo multitoque precisa rastrear dedos individuais enquanto eles se movem simultaneamente na tela. Uma aplicação típica é um programa de pintura a dedo. Você quer que o usuário seja capaz de desenhar com um único dedo, mas também desenhar com vários dedos ao mesmo tempo. Como seu programa processa vários eventos de toque, ele precisa distinguir entre esses dedos.
Quando um dedo toca pela primeira vez na tela, o iOS cria um UITouch
objeto para esse dedo. Esse objeto permanece o mesmo que o dedo se move na tela e, em seguida, levanta da tela, momento em que o objeto é descartado. Para manter o controle dos dedos, um programa deve evitar armazenar esse UITouch
objeto diretamente. Em vez disso, ele pode usar a Handle
propriedade de tipo IntPtr
para identificar exclusivamente esses UITouch
objetos.
Quase sempre, um programa que rastreia dedos individuais mantém um dicionário para rastreamento por toque. Para um programa iOS, a chave do dicionário é o Handle
valor que identifica um dedo específico. O valor do dicionário depende do aplicativo. No programa de exemplo, cada traçado do dedo (do toque à liberação) é associado a um objeto que contém todas as informações necessárias para renderizar a linha desenhada com esse dedo. O programa define uma pequena FingerPaintPolyline
classe para este fim:
class FingerPaintPolyline
{
public FingerPaintPolyline()
{
Path = new CGPath();
}
public CGColor Color { set; get; }
public float StrokeWidth { set; get; }
public CGPath Path { private set; get; }
}
Cada polilinha tem uma cor, uma largura de traçado e um objeto gráfico CGPath
iOS para acumular e renderizar vários pontos da linha à medida que ela está sendo desenhada.
Todo o resto do código mostrado abaixo está contido em um UIView
derivado chamado FingerPaintCanvasView
. Essa classe mantém um dicionário de objetos do tipo FingerPaintPolyline
durante o tempo em que eles estão sendo ativamente desenhados por um ou mais dedos:
Dictionary<IntPtr, FingerPaintPolyline> inProgressPolylines = new Dictionary<IntPtr, FingerPaintPolyline>();
Este dicionário permite que a exibição obtenha rapidamente as FingerPaintPolyline
informações associadas a cada dedo com base na Handle
propriedade do UITouch
objeto.
A FingerPaintCanvasView
classe também mantém um List
objeto para as polilinhas que foram concluídas:
List<FingerPaintPolyline> completedPolylines = new List<FingerPaintPolyline>();
Os objetos estão List
na mesma ordem em que foram desenhados.
FingerPaintCanvasView
substitui cinco métodos definidos por View
:
As várias Touches
substituições acumulam os pontos que compõem as polilinhas.
A substituição [Draw
] desenha as polilinhas concluídas e, em seguida, as polilinhas em andamento:
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);
}
}
}
Cada uma das Touches
substituições relata potencialmente as ações de vários dedos, indicadas por um ou mais UITouch
objetos armazenados no touches
argumento para o método. As TouchesBegan
substituições percorrem esses objetos. Para cada UITouch
objeto, o método cria e inicializa um novo FingerPaintPolyline
objeto, incluindo o armazenamento do local inicial do dedo obtido do LocationInView
método. Esse FingerPaintPolyline
objeto é adicionado ao InProgressPolylines
dicionário usando a Handle
UITouch
propriedade do objeto como uma chave de dicionário:
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();
}
O método é concluído chamando SetNeedsDisplay
para gerar uma chamada para a Draw
substituição e atualizar a tela.
À medida que o dedo ou os dedos se movem na tela, o View
recebe várias chamadas para sua TouchesMoved
substituição. Essa substituição também faz um loop pelos UITouch
objetos armazenados no touches
argumento e adiciona o local atual do dedo ao caminho gráfico:
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();
}
A touches
coleção contém apenas os UITouch
objetos para os dedos que foram movidos desde a última chamada para TouchesBegan
ou TouchesMoved
. Se você precisar de UITouch
objetos correspondentes a todos os dedos atualmente em contato com a tela, essas informações estarão disponíveis por meio AllTouches
da propriedade do UIEvent
argumento para o método.
A TouchesEnded
substituição tem dois trabalhos. Ele deve adicionar o último ponto ao caminho gráfico e transferir o FingerPaintPolyline
objeto do inProgressPolylines
dicionário para a completedPolylines
lista:
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();
}
A TouchesCancelled
substituição é tratada simplesmente abandonando o FingerPaintPolyline
objeto no dicionário:
public override void TouchesCancelled(NSSet touches, UIEvent evt)
{
base.TouchesCancelled(touches, evt);
foreach (UITouch touch in touches.Cast<UITouch>())
{
inProgressPolylines.Remove(touch.Handle);
}
SetNeedsDisplay();
}
Em conjunto, esse processamento permite que o programa de amostra rastreie dedos individuais e desenhe os resultados na tela:
Agora você viu como você pode rastrear dedos individuais na tela e distinguir entre eles.