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

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

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

Упражнение в рисовании пальцев

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

Пример решения включает это событие отслеживания сенсорного ввода. Проект библиотеки .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);
        }
    }
    ...
}

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

Снимок экрана с тремя изображениями страницы рисования пальцами

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