SkiaSharp에서 손가락 그림판

Download Sample 샘플 다운로드

손가락을 사용하여 캔버스에 페인트합니다.

개체를 SKPath 지속적으로 업데이트하고 표시할 수 있습니다. 이 기능을 사용하면 손가락 그리기 프로그램과 같은 대화형 그리기에 경로를 사용할 수 있습니다.

An exercise in finger painting

터치 지원 Xamarin.Forms 은 화면에서 개별 손가락을 추적하는 것을 허용하지 않으므로 Xamarin.Forms 터치 추적 효과가 개발되어 추가 터치 지원을 제공합니다. 이 효과는 효과에서 이벤트 호출 문서에 설명되어 있습니다. 샘플 프로그램 터치 추적 효과 데모 에는 손가락 그리기 프로그램을 포함하여 SkiaSharp를 사용하는 두 페이지가 포함되어 있습니다.

SkiaSharpFormsDemos 솔루션에는 이 터치 추적 이벤트가 포함됩니다. .NET Standard 라이브러리 프로젝트에는 클래스, TouchActionType 열거형, TouchActionEventHandler 대리자 및 클래스가 TouchActionEventArgs 포함됩니다TouchEffect. 각 플랫폼 프로젝트에는 해당 플랫폼에 대한 클래스가 포함 TouchEffect 되며 iOS 프로젝트에는 클래스도 포함됩니다 TouchRecognizer .

SkiaSharpFormsDemos핑거 그림판 페이지는 손가락 그리기의 간소화된 구현입니다. 색이나 스트로크 너비를 선택할 수 없으며 캔버스를 지울 방법이 없으며 아트워크를 저장할 수 없습니다.

Finger그림판Page.xaml 파일은 단일 셀 Grid 에 넣고 다음Grid을 연결합니다TouchEffect.SKCanvasView

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

직접 연결해도 TouchEffectSKCanvasView 모든 플랫폼에서 작동하지는 않습니다.

Finger그림판Page.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 하나 이상의 손가락으로 현재 그려지는 경로를 저장합니다. 사전 키는 터치 이벤트와 함께 제공되는 터치 ID입니다. completedPaths 필드는 경로를 그리는 손가락이 화면에서 들어올릴 때 완료된 경로의 컬렉션입니다.

TouchAction 처리기는 이러한 두 컬렉션을 관리합니다. 손가락이 화면을 처음 터치하면 새 SKPath 손가락이 추가 inProgressPaths됩니다. 손가락이 이동하면 경로에 추가 지점이 추가됩니다. 손가락을 놓으면 경로가 컬렉션으로 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 변환을 탐색하는 것입니다.