共用方式為


線條和筆觸端點

瞭解如何使用 SkiaSharp 繪製具有不同筆劃上限的線條

在SkiaSharp中,轉譯單行與轉譯一系列連接的直線非常不同。 不過,即使繪製單一線條,通常也需要為線條提供特定的筆劃寬度。 隨著這些線條變寬,線條結尾的外觀也變得很重要。 線條結尾的外觀稱為 筆觸上限

三個筆劃上限選項

針對繪製單一線條,定義簡單DrawLine方法,SKCanvas其自變數會指出線條與 SKPaint 對象的開始和結束座標:

canvas.DrawLine (x0, y0, x1, y1, paint);

根據預設, StrokeWidth 新具現化 SKPaint 對象的 屬性是0,在呈現粗細一行圖元時,其效果與值1相同。 這在手機等高解析度裝置上顯得非常薄,因此您可能會想要將 設定 StrokeWidth 為較大的值。 但是,一旦您開始繪製大小粗細的線條,就會引發另一個問題:如何轉譯這些粗線的開始和結尾?

線條開頭和結尾的外觀稱為 線條上限 ,或在Skia中為 筆觸上限。 此內容中的“cap”一詞指的是一種帽子,即位在行尾的東西。 您可以將 物件的 屬性SKPaint設定StrokeCap為列舉的SKStrokeCap下列其中一個成員:

  • Butt (預設值)
  • Square
  • Round

這些最適合使用範例程序來說明。 範例程式的 SkiaSharp Lines 和 Paths 區段會以StrokeCapsPage類別為基礎的標題為 Stroke Caps 的頁面開始。 此頁面會 PaintSurface 定義事件處理程式,其會迴圈查看列舉的 SKStrokeCap 三個成員,並顯示列舉成員的名稱,並使用該筆劃上限繪製線條:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    SKPaint textPaint = new SKPaint
    {
        Color = SKColors.Black,
        TextSize = 75,
        TextAlign = SKTextAlign.Center
    };

    SKPaint thickLinePaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Orange,
        StrokeWidth = 50
    };

    SKPaint thinLinePaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Black,
        StrokeWidth = 2
    };

    float xText = info.Width / 2;
    float xLine1 = 100;
    float xLine2 = info.Width - xLine1;
    float y = textPaint.FontSpacing;

    foreach (SKStrokeCap strokeCap in Enum.GetValues(typeof(SKStrokeCap)))
    {
        // Display text
        canvas.DrawText(strokeCap.ToString(), xText, y, textPaint);
        y += textPaint.FontSpacing;

        // Display thick line
        thickLinePaint.StrokeCap = strokeCap;
        canvas.DrawLine(xLine1, y, xLine2, y, thickLinePaint);

        // Display thin line
        canvas.DrawLine(xLine1, y, xLine2, y, thinLinePaint);
        y += 2 * textPaint.FontSpacing;
    }
}

針對列舉的每個 SKStrokeCap 成員,處理程式會繪製兩條線,一行的筆劃粗細為 50 像素,另一行位於上方,筆劃粗細為兩個圖元。 第二行旨在說明線條粗細和筆觸上限無關的線條幾何開始和結尾:

[筆觸上限] 頁面的三重螢幕快照

如您所見, SquareRound 筆劃上限可有效地將線條的長度延伸一半的筆劃寬度,並在結尾再次延伸。 當需要判斷轉譯圖形對象的維度時,此延伸模組就變得很重要。

類別 SKCanvas 也包含另一個繪製多行的方法,有些特別:

DrawPoints (SKPointMode mode, points, paint)

參數 points 是值的陣列 SKPoint ,而且 mode 是 列舉的成員 SKPointMode ,其有三個成員:

  • Points 轉譯個別點
  • Lines 以連接每一組點
  • Polygon 連接所有連續點

[ 多行] 頁面示範這個方法。 MultipleLinesPage.xaml 檔案會具現化兩Picker個檢視,讓您選取列舉的成員SKPointMode和列舉的成員SKStrokeCap

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp;assembly=SkiaSharp"
             xmlns:skiaforms="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="SkiaSharpFormsDemos.Paths.MultipleLinesPage"
             Title="Multiple Lines">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Picker x:Name="pointModePicker"
                Title="Point Mode"
                Grid.Row="0"
                Grid.Column="0"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type skia:SKPointMode}">
                    <x:Static Member="skia:SKPointMode.Points" />
                    <x:Static Member="skia:SKPointMode.Lines" />
                    <x:Static Member="skia:SKPointMode.Polygon" />
                </x:Array>
            </Picker.ItemsSource>
            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>

        <Picker x:Name="strokeCapPicker"
                Title="Stroke Cap"
                Grid.Row="0"
                Grid.Column="1"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type skia:SKStrokeCap}">
                    <x:Static Member="skia:SKStrokeCap.Butt" />
                    <x:Static Member="skia:SKStrokeCap.Round" />
                    <x:Static Member="skia:SKStrokeCap.Square" />
                </x:Array>
            </Picker.ItemsSource>
            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>

        <skiaforms:SKCanvasView x:Name="canvasView"
                                PaintSurface="OnCanvasViewPaintSurface"
                                Grid.Row="1"
                                Grid.Column="0"
                                Grid.ColumnSpan="2" />
    </Grid>
</ContentPage>

請注意,SkiaSharp 命名空間宣告有點不同,因為SkiaSharp需要命名空間來參考 和 SKStrokeCap 列舉的成員SKPointMode。 這 SelectedIndexChangedPicker 個檢視的處理程式只會使 物件失效 SKCanvasView

void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
    if (canvasView != null)
    {
        canvasView.InvalidateSurface();
    }
}

這個處理程式需要檢查物件是否存在SKCanvasView,因為當 的 屬性Picker設定為 XAML 檔案中的 0 時SelectedIndex,會先呼叫 事件處理程式,而且會在 具現化之前SKCanvasView發生。

處理程式 PaintSurface 會從 Picker 檢視中取得兩個列舉值:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    // Create an array of points scattered through the page
    SKPoint[] points = new SKPoint[10];

    for (int i = 0; i < 2; i++)
    {
        float x = (0.1f + 0.8f * i) * info.Width;

        for (int j = 0; j < 5; j++)
        {
            float y = (0.1f + 0.2f * j) * info.Height;
            points[2 * j + i] = new SKPoint(x, y);
        }
    }

    SKPaint paint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.DarkOrchid,
        StrokeWidth = 50,
        StrokeCap = (SKStrokeCap)strokeCapPicker.SelectedItem
    };

    // Render the points by calling DrawPoints
    SKPointMode pointMode = (SKPointMode)pointModePicker.SelectedItem;
    canvas.DrawPoints(pointMode, points, paint);
}

螢幕快照顯示各種 Picker 選取專案:

多行頁面的三重螢幕快照

左邊的 i 電話 顯示列舉成員如何在SKPointMode.Points線條上限為 ButtSquare時,將DrawPoints陣列中的每個SKPoint點轉譯為正方形。 如果線條上限為 Round,則會轉譯圓形。

Android 螢幕快照顯示 的結果 SKPointMode.Lines。 在此案例Round中,方法DrawPoints會使用指定的行上限,在每個值組SKPoint之間繪製一條線。

當您改用 SKPointMode.Polygon時,會在陣列中連續的點之間繪製線條,但如果您仔細查看,您會看到這些線條未連接。 每一行都會以指定的行大寫開頭和結尾。 如果您選取 Round 上限,則行似乎已連線,但實際上並未連線。

是否連接線條是使用圖形路徑的重要層面。