Freigeben über


Finger Painting in SkiaSharp

Verwenden Sie Ihre Finger, um auf dem Zeichenbereich zu zeichnen.

Ein SKPath Objekt kann kontinuierlich aktualisiert und angezeigt werden. Mit diesem Feature kann ein Pfad für interaktive Zeichnung verwendet werden, z. B. in einem Finger-Painting-Programm.

Eine Übung beim Fingermalen

Die Touchunterstützung Xamarin.Forms lässt das Nachverfolgen einzelner Finger auf dem Bildschirm nicht zu, sodass ein Xamarin.Forms Touch-Tracking-Effekt entwickelt wurde, um zusätzliche Touchunterstützung zu bieten. Dieser Effekt wird im Artikel "Aufrufen von Ereignissen aus Effekten" beschrieben. Das Beispielprogramm enthält zwei Seiten, die SkiaSharp verwenden, einschließlich eines Finger-Painting-Programms.

Die Beispiellösung enthält dieses Ereignis zur Touchverfolgung. Das .NET Standard-Bibliotheksprojekt enthält die TouchEffect Klasse, die TouchActionType Enumeration, den TouchActionEventHandler Delegaten und die TouchActionEventArgs Klasse. Jedes der Plattformprojekte enthält eine TouchEffect Klasse für diese Plattform. Das iOS-Projekt enthält auch eine TouchRecognizer Klasse.

Die Finger Paint-Seite in SkiaSharpFormsDemos ist eine vereinfachte Implementierung von Finger painting. Die Auswahl von Farbe oder Strichbreite ist nicht zulässig, sie hat keine Möglichkeit, den Zeichenbereich zu löschen, und Natürlich können Sie Ihre Grafiken nicht speichern.

Die Datei "FingerPaintPage.xaml " fügt die SKCanvasView Datei in eine einzelne Zelle Grid ein und fügt die Datei TouchEffect an folgendes Gridan:

<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>

Das direkte Anfügen der TouchEffect Direkt an die SKCanvasView Plattform funktioniert nicht unter allen Plattformen.

Die FingerPaintPage.xaml.cs CodeBehind-Datei definiert zwei Auflistungen zum Speichern der SKPath Objekte sowie ein SKPaint Objekt zum Rendern dieser Pfade:

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

Wie der Name schon sagt, speichert das inProgressPaths Wörterbuch die Pfade, die derzeit von einem oder mehreren Fingern gezeichnet werden. Die Wörterbuchtaste ist die Touch-ID, die die Touchereignisse begleitet. Das completedPaths Feld ist eine Sammlung von Pfaden, die beendet wurden, wenn ein Finger, der den Vom Bildschirm angehobenen Pfad zeichnete.

Der TouchAction Handler verwaltet diese beiden Auflistungen. Wenn ein Finger zum ersten Mal den Bildschirm berührt, wird ein neues SKPath hinzugefügt inProgressPaths. Während dieses Fingers bewegt, werden dem Pfad zusätzliche Punkte hinzugefügt. Wenn der Finger losgelassen wird, wird der Pfad in die completedPaths Sammlung übertragen. Sie können mit mehreren Fingern gleichzeitig zeichnen. Nach jeder Änderung an einem der Pfade oder Auflistungen wird die SKCanvasView Eigenschaft ungültig:

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

Die Punkte, die die Touch-Tracking-Ereignisse begleiten, sind Xamarin.Forms Koordinaten. Diese müssen in SkiaSharp-Koordinaten konvertiert werden, die Pixel sind. Das ist der Zweck der ConvertToPixel Methode.

Der PaintSurface Handler rendert dann einfach beide Auflistungen von Pfaden. Die zuvor abgeschlossenen Pfade werden unterhalb der laufenden Pfade angezeigt:

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

Ihre Fingerbilder sind nur durch Ihr Talent begrenzt:

Screenshot: Seite „Finger Paint“

Sie haben nun gesehen, wie Sie Linien zeichnen und Kurven mithilfe parametrischer Formeln definieren. Ein späterer Abschnitt zu SkiaSharp Kurven und Pfaden deckt die verschiedenen Arten von Kurven ab, die SKPath unterstützt werden. Aber eine nützliche Voraussetzung ist eine Erkundung von SkiaSharp Transforms.