Compartilhar via


Pintura a dedo em SkiaSharp

Use os dedos para pintar na tela.

Um SKPath objeto pode ser continuamente atualizado e exibido. Esse recurso permite que um caminho seja usado para desenho interativo, como em um programa de pintura a dedo.

Um exercício de pintura a dedo

O suporte ao toque não Xamarin.Forms permite rastrear dedos individuais na tela, portanto, um Xamarin.Forms efeito de rastreamento de toque foi desenvolvido para fornecer suporte de toque adicional. Esse efeito é descrito no artigo Invocando eventos de efeitos. O programa de exemplo inclui duas páginas que usam SkiaSharp, incluindo um programa de pintura a dedo.

A solução de exemplo inclui esse evento de rastreamento por toque. O projeto de biblioteca do .NET Standard inclui a TouchEffect classe, a TouchActionType enumeração, o TouchActionEventHandler delegado e a TouchActionEventArgs classe. Cada um dos projetos da plataforma inclui uma TouchEffect classe para essa plataforma, o projeto iOS também contém uma TouchRecognizer classe.

A página Finger Paint no SkiaSharpFormsDemos é uma implementação simplificada da pintura a dedo. Ele não permite selecionar cor ou largura de traçado, não tem como limpar a tela e, claro, você não pode salvar seu trabalho artístico.

O arquivo FingerPaintPage.xaml coloca o SKCanvasView em uma única célula Grid e anexa o 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>

Anexar o TouchEffect diretamente ao SKCanvasView não funciona em todas as plataformas.

O arquivo code-behind FingerPaintPage.xaml.cs define duas coleções para armazenar os SKPath objetos, bem como um SKPaint objeto para renderizar esses caminhos:

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();
    }
    ...
}

Como o nome sugere, o dicionário armazena inProgressPaths os caminhos que estão sendo desenhados por um ou mais dedos. A chave do dicionário é o ID de toque que acompanha os eventos de toque. O completedPaths campo é uma coleção de caminhos que foram concluídos quando um dedo que estava desenhando o caminho levantou da tela.

O TouchAction manipulador gerencia essas duas coleções. Quando um dedo toca pela primeira vez na tela, um novo SKPath é adicionado ao inProgressPaths. À medida que esse dedo se move, pontos adicionais são adicionados ao caminho. Quando o dedo é liberado, o caminho é transferido para a completedPaths coleção. Você pode pintar com vários dedos simultaneamente. Após cada alteração em um dos caminhos ou coleções, o SKCanvasView é invalidado:

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));
    }
}

Os pontos que acompanham os eventos de rastreamento por toque são Xamarin.Forms coordenadas, que devem ser convertidas em coordenadas SkiaSharp, que são pixels. Esse é o ConvertToPixel objetivo do método.

O PaintSurface manipulador, em seguida, simplesmente renderiza ambas as coleções de caminhos. Os caminhos concluídos anteriormente aparecem abaixo dos caminhos em andamento:

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);
        }
    }
    ...
}

Suas pinturas de dedo são limitadas apenas pelo seu talento:

Captura de tela tripla da página Pintura a Dedo

Agora você já viu como desenhar linhas e definir curvas usando equações paramétricas. Uma seção posterior sobre SkiaSharp Curves and Paths cobre os vários tipos de curvas que SKPath suporta. Mas um pré-requisito útil é uma exploração das Transformações SkiaSharp.