Роспись пальцев в SkiaSharp

Download Sample Скачайте пример

Используйте пальцы, чтобы нарисовать на холсте.

Объект SKPath можно постоянно обновлять и отображать. Эта функция позволяет использовать путь для интерактивного рисования, например в программе рисования пальцев.

An exercise in finger painting

Поддержка сенсорного ввода не позволяет отслеживать отдельные пальцы на экране, поэтому Xamarin.Forms эффект сенсорного Xamarin.Forms отслеживания был разработан, чтобы обеспечить дополнительную поддержку сенсорного ввода. Этот эффект описан в статье "Вызов событий из эффектов". Пример программы Touch-Tracking Effect Demos включает две страницы , которые используют SkiaSharp, включая программу рисования пальцев.

Решение SkiaSharpFormsDemos включает это событие сенсорного отслеживания. Проект библиотеки .NET Standard включает TouchEffect класс, TouchActionType перечисление, TouchActionEventHandler делегат и TouchActionEventArgs класс. Каждый из проектов платформы включает TouchEffect класс для этой платформы; проект iOS также содержит TouchRecognizer класс.

Страница "Палец краска" в SkiaSharpFormsDemos является упрощенной реализацией рисования пальцев. Он не позволяет выбирать цвет или ширину росчерка, он не имеет способа очистить холст, и, конечно, вы не можете сохранить изображение.

Файл FingerPaintPage.xaml помещает SKCanvasView его в одну ячейку Grid и присоединяет TouchEffect его к этомуGrid:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             xmlns:tt="clr-namespace:TouchTracking"
             x:Class="SkiaSharpFormsDemos.Paths.FingerPaintPage"
             Title="Finger Paint">

    <Grid BackgroundColor="White">
        <skia:SKCanvasView x:Name="canvasView"
                           PaintSurface="OnCanvasViewPaintSurface" />
        <Grid.Effects>
            <tt:TouchEffect Capture="True"
                            TouchAction="OnTouchEffectAction" />
        </Grid.Effects>
    </Grid>
</ContentPage>

Присоединение TouchEffect непосредственно к нему SKCanvasView не работает на всех платформах.

Файл кода FingerPaintPage.xaml.cs определяет две коллекции для хранения SKPath объектов, а также SKPaint объект для отрисовки этих путей:

public partial class FingerPaintPage : ContentPage
{
    Dictionary<long, SKPath> inProgressPaths = new Dictionary<long, SKPath>();
    List<SKPath> completedPaths = new List<SKPath>();

    SKPaint paint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Blue,
        StrokeWidth = 10,
        StrokeCap = SKStrokeCap.Round,
        StrokeJoin = SKStrokeJoin.Round
    };

    public FingerPaintPage()
    {
        InitializeComponent();
    }
    ...
}

Как показано в названии, inProgressPaths словарь хранит пути, которые в настоящее время рисуются одним или несколькими пальцами. Ключ словаря — это идентификатор сенсорного ввода, который сопровождает события касания. Поле completedPaths представляет собой коллекцию путей, которые были завершены, когда пальцем, который рисовал путь, поднятый с экрана.

Обработчик TouchAction управляет этими двумя коллекциями. Когда пальцем сначала прикасается к экрану, добавляется inProgressPathsновоеSKPath. По мере перемещения пальца в путь добавляются дополнительные точки. При освобождении пальца путь передается в коллекцию completedPaths . Вы можете одновременно рисовать с несколькими пальцами. После каждого изменения на один из путей или коллекций будет SKCanvasView отменено:

public partial class FingerPaintPage : ContentPage
{
    ...
    void OnTouchEffectAction(object sender, TouchActionEventArgs args)
    {
        switch (args.Type)
        {
            case TouchActionType.Pressed:
                if (!inProgressPaths.ContainsKey(args.Id))
                {
                    SKPath path = new SKPath();
                    path.MoveTo(ConvertToPixel(args.Location));
                    inProgressPaths.Add(args.Id, path);
                    canvasView.InvalidateSurface();
                }
                break;

            case TouchActionType.Moved:
                if (inProgressPaths.ContainsKey(args.Id))
                {
                    SKPath path = inProgressPaths[args.Id];
                    path.LineTo(ConvertToPixel(args.Location));
                    canvasView.InvalidateSurface();
                }
                break;

            case TouchActionType.Released:
                if (inProgressPaths.ContainsKey(args.Id))
                {
                    completedPaths.Add(inProgressPaths[args.Id]);
                    inProgressPaths.Remove(args.Id);
                    canvasView.InvalidateSurface();
                }
                break;

            case TouchActionType.Cancelled:
                if (inProgressPaths.ContainsKey(args.Id))
                {
                    inProgressPaths.Remove(args.Id);
                    canvasView.InvalidateSurface();
                }
                break;
        }
    }
    ...
    SKPoint ConvertToPixel(Point pt)
    {
        return new SKPoint((float)(canvasView.CanvasSize.Width * pt.X / canvasView.Width),
                           (float)(canvasView.CanvasSize.Height * pt.Y / canvasView.Height));
    }
}

Точки, сопровождающие события сенсорного отслеживания, являются Xamarin.Forms координатами. Они должны быть преобразованы в координаты SkiaSharp, которые являются пикселями. Это цель ConvertToPixel метода.

Затем PaintSurface обработчик просто отрисовывает обе коллекции путей. Предыдущие завершенные пути отображаются под путями, которые выполняются:

public partial class FingerPaintPage : ContentPage
{
    ...
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKCanvas canvas = args.Surface.Canvas;
        canvas.Clear();

        foreach (SKPath path in completedPaths)
        {
            canvas.DrawPath(path, paint);
        }

        foreach (SKPath path in inProgressPaths.Values)
        {
            canvas.DrawPath(path, paint);
        }
    }
    ...
}

Ваши рисунки пальцев ограничены только вашим талантом:

Triple screenshot of the Finger Paint page

Теперь вы узнали, как рисовать линии и определять кривые с помощью уравнений параметрики. Более поздний раздел о кривых и путях SkiaSharp охватывает различные типы кривых, которые SKPath поддерживают. Но полезное условие заключается в изучении преобразований SkiaSharp.