Мультисенсорные палец отслеживания в Xamarin.iOSMulti-Touch Finger Tracking in Xamarin.iOS

В этом документе показано, как отслеживать события касания с несколькими пальцамиThis document demonstrates how to track touch events from multiple fingers

Бывают случаи, когда Мультисенсорные приложения нужно отслеживать движение, при перемещении одновременно на экране.There are times when a multi-touch application needs to track individual fingers as they move simultaneously on the screen. Одним из типичных приложений является finger-paint программы.One typical application is a finger-paint program. Требуется, чтобы пользователь мог для рисования с одним пальцем, но также для рисования пальцами несколько за один раз.You want the user to be able to draw with a single finger, but also to draw with multiple fingers at once. Как приложение обрабатывает несколько событий сенсорного ввода, ему необходимо различать эти пальцами.As your program processes multiple touch events, it needs to distinguish between these fingers.

При первом касании пальцем экрана, iOS создает UITouch объект для этого палец.When a finger first touches the screen, iOS creates a UITouch object for that finger. Этот объект остается равным палец перемещается на экране, а затем поднимает на экране, после чего удаляется объект.This object remains the same as the finger moves on the screen and then lifts from the screen, at which point the object is disposed. Для отслеживания пальцами, программа не храните это UITouch объекта напрямую.To keep track of fingers, a program should avoid storing this UITouch object directly. Вместо этого можно использовать Handle свойство типа IntPtr для уникальной идентификации этих UITouch объектов.Instead, it can use the Handle property of type IntPtr to uniquely identify these UITouch objects.

Почти всегда это программа, которая отслеживает движение ведение словаря для отслеживания сенсорного управления.Almost always, a program that tracks individual fingers maintains a dictionary for touch tracking. Для приложения iOS является ключом словаря Handle значение, определяющее конкретной точки касания.For an iOS program, the dictionary key is the Handle value that identifies a particular finger. Значение словаря зависит от приложения.The dictionary value depends on the application. В FingerPaint программа, каждый палец stroke (от сенсорного ввода для освобождения) связана с объект, содержащий всю информацию, необходимую для отображения линии, нарисованных при помощи этого палец.In the FingerPaint program, each finger stroke (from touch to release) is associated with an object that contains all the information necessary to render the line drawn with that finger. Программа определяет небольшой FingerPaintPolyline класс для этой цели:The program defines a small FingerPaintPolyline class for this purpose:

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 объекта накапливаются и отобразить несколько точек линии, его написания.Each polyline has a color, a stroke width, and an iOS graphics CGPath object to accumulate and render multiple points of the line as it's being drawn.

Все остальные приведенный ниже код, содержащийся в UIView с именем FingerPaintCanvasView.All the rest of the code shown below is contained in a UIView derivative named FingerPaintCanvasView. Что класс поддерживает словарь объектов типа FingerPaintPolyline во время они активно рисуются с одним или несколькими пальцами:That class maintains a dictionary of objects of type FingerPaintPolyline during the time that they are actively being drawn by one or more fingers:

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

Этот словарь позволяет быстро получить представление FingerPaintPolyline на основе сведений, связанных с каждого пальца Handle свойство UITouch объекта.This dictionary allows the view to quickly obtain the FingerPaintPolyline information associated with each finger based on the Handle property of the UITouch object.

FingerPaintCanvasView Класс также поддерживает List объект для ломаные линии, будут завершены:The FingerPaintCanvasView class also maintains a List object for the polylines that have been completed:

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

Объекты в этом List находятся в том же порядке, что они были показаны.The objects in this List are in the same order that they were drawn.

FingerPaintCanvasView переопределяет пять методов, определенных View:FingerPaintCanvasView overrides five methods defined by View:

Различные Touches переопределения накапливать точки, составляющие ломаные линии.The various Touches overrides accumulate the points that make up the polylines.

[Draw] Переопределение рисует завершенного ломаные линии, а затем выполняется ломаные линии:The [Draw] override draws the completed polylines and then the in-progress polylines:

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 аргумента метода.Each of the Touches overrides potentially reports the actions of multiple fingers, indicated by one or more UITouch objects stored in the touches argument to the method. TouchesBegan Переопределения перебор этих объектов.The TouchesBegan overrides loop through these objects. Для каждого UITouch объекта, метод создает и инициализирует новую задачу FingerPaintPolyline объекта, включая хранение первоначального расположения элемента палец, полученный из LocationInView метод.For each UITouch object, the method creates and initializes a new FingerPaintPolyline object, including storing the initial location of the finger obtained from the LocationInView method. Это FingerPaintPolyline объект добавляется InProgressPolylines словаря с помощью Handle свойство UITouch объекта в качестве ключа словаря:This FingerPaintPolyline object is added to the InProgressPolylines dictionary using the Handle property of the UITouch object as a dictionary key:

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 переопределить и обновление экрана.The method concludes by calling SetNeedsDisplay to generate a call to the Draw override and to update the screen.

Перемещении пальца или пальцев на экране View получает несколько вызовов его TouchesMoved переопределить.As the finger or fingers move on the screen, the View gets multiple calls to its TouchesMoved override. Это переопределение аналогичным образом просматривает UITouch объектов, хранящихся в touches аргумента и добавляет текущее расположение палец графический контур:This override similarly loops through the UITouch objects stored in the touches argument and adds the current location of the finger to the graphics path:

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.The touches collection contains only those UITouch objects for the fingers that have moved since the last call to TouchesBegan or TouchesMoved. При обращении в службу UITouch объектов, соответствующий все пальцами, в настоящее время с экрана, эти сведения можно получить через AllTouches свойство UIEvent аргумента метода.If you ever need UITouch objects corresponding to all the fingers currently in contact with the screen, that information is available through the AllTouches property of the UIEvent argument to the method.

TouchesEnded Переопределение выполняет следующие задания.The TouchesEnded override has two jobs. Он должен добавить точки графический контур и передачи FingerPaintPolyline объекта из inProgressPolylines словаря completedPolylines списка:It must add the last point to the graphics path, and transfer the FingerPaintPolyline object from the inProgressPolylines dictionary to the completedPolylines list:

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 объекта в словаре:The TouchesCancelled override is handled by simply abandoning the FingerPaintPolyline object in the dictionary:

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

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

В общей сложности эта обработка позволяет FingerPaint программы отслеживать движение и отображать результаты на экране:Altogether, this processing allows the FingerPaint program to track individual fingers and draw the results on the screen:

Теперь вы знаете, как можно отслеживать отдельные пальцев на экране и различать их.You've now seen how you can track individual fingers on the screen and distinguish among them.