Fingermalerei in SkiaSharp

Beispiel herunterladen Das Beispiel herunterladen

Verwenden Sie Ihre Finger, um auf der Canvas zu malen.

Ein SKPath Objekt kann kontinuierlich aktualisiert und angezeigt werden. Mit dieser Funktion kann ein Pfad für interaktives Zeichnen verwendet werden, z. B. in einem Programm zum Malen von Fingern.

Eine Übung beim Fingermalen

Die Touchunterstützung in Xamarin.Forms erlaubt nicht das Nachverfolgen einzelner Finger auf dem Bildschirm, 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 Touch-Tracking Effect Demos umfasst zwei Seiten, die SkiaSharp verwenden, einschließlich eines Programms zum Malen von Fingern.

Die SkiaSharpFormsDemos-Lösung umfasst dieses Touchtracking-Ereignis. Das .NET Standard-Bibliotheksprojekt umfasst 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 Seite Finger Paint in SkiaSharpFormsDemos ist eine vereinfachte Implementierung von Fingermalen. Es ist nicht zulässig, Farbe oder Strichbreite auszuwählen, es gibt keine Möglichkeit, die Canvas zu löschen, und natürlich können Sie Ihr Kunstwerk nicht speichern.

Die Datei FingerPaintPage.xaml fügt das SKCanvasView in eine einzelne Zelle Grid ein und fügt das 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 SKCanvasView Anfügen des TouchEffect funktioniert nicht auf allen Plattformen.

Die CodeBehind-Datei FingerPaintPage.xaml.cs definiert zwei Sammlungen 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 mit einem oder mehreren Fingern gezeichnet werden. Der Wörterbuchschlüssel ist die Touch-ID, die die Touchereignisse begleitet. Das completedPaths Feld ist eine Sammlung von Pfaden, die beendet wurden, als ein Finger, der den Pfad zeichnete, vom Bildschirm gehoben wurde.

Der TouchAction Handler verwaltet diese beiden Auflistungen. Wenn ein Finger den Bildschirm zum ersten Mal berührt, wird ein neuer SKPath hinzugefügt inProgressPaths. Wenn sich dieser Finger bewegt, werden dem Pfad zusätzliche Punkte hinzugefügt. Wenn der Finger losgelassen wird, wird der Pfad an die completedPaths Auflistung übertragen. Sie können mit mehreren Fingern gleichzeitig malen. Nach jeder Änderung an einem der Pfade oder Auflistungen wird ungültig 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));
    }
}

Die Punkte, die die Touchverfolgungsereignisse begleiten, sind Xamarin.Forms Koordinaten. Diese müssen in SkiaSharp-Koordinaten konvertiert werden, bei denen es sich um Pixel handelt. Das ist der Zweck der ConvertToPixel Methode.

Der PaintSurface Handler rendert dann einfach beide Auflistungen von Pfaden. Die zuvor abgeschlossenen Pfade werden unter den laufenden Pfaden 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:

Sie haben nun erfahren, wie Sie Linien zeichnen und Kurven mithilfe parametrischer Formeln definieren. Ein späterer Abschnitt zu SkiaSharp Kurven und Pfaden behandelt die verschiedenen Arten von Kurven, die unterstützt SKPath werden. Eine nützliche Voraussetzung ist jedoch eine Untersuchung von SkiaSharp-Transformationen.