Отслеживание нескольких сенсорных пальцев в 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; }
}
Каждая полилайн имеет цвет, ширину штриха и графический CGPath
объект iOS для накапливания и отрисовки нескольких точек линии по мере рисования.
Весь остальной код, показанный ниже, содержится в производном UIView
именованном FingerPaintCanvasView
коде. Этот класс поддерживает словарь объектов типа FingerPaintPolyline
во время их активного рисования одним или несколькими пальцами:
Dictionary<IntPtr, FingerPaintPolyline> inProgressPolylines = new Dictionary<IntPtr, FingerPaintPolyline>();
Этот словарь позволяет представлению быстро получать FingerPaintPolyline
сведения, связанные с каждым пальцем на Handle
основе свойства UITouch
объекта.
Класс 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
переопределения потенциально сообщает действия нескольких пальцев, указанные одним или несколькими UITouch
объектами, хранящимися в аргументе touches
в методе. Переопределяет TouchesBegan
цикл по этим объектам. Для каждого UITouch
объекта метод создает и инициализирует новый FingerPaintPolyline
объект, включая хранение исходного расположения пальца, полученного из LocationInView
метода. Этот FingerPaintPolyline
объект добавляется в InProgressPolylines
словарь с помощью Handle
свойства UITouch
объекта в качестве ключа словаря:
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
имеет два задания. Он должен добавить последнюю точку в графический путь и передать FingerPaintPolyline
объект из inProgressPolylines
словаря в 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();
}
В целом эта обработка позволяет образцу программы отслеживать отдельные пальцы и выводить результаты на экране:
Теперь вы узнали, как можно отслеживать отдельные пальцы на экране и различать их.