共用方式為


SkiaSharp 中的點和虛線

掌握在 SkiaSharp 中繪製虛線和虛線的複雜

SkiaSharp 可讓您繪製不是實心的線條,而是由點和虛線組成:

虛線

您可以使用路徑效果來執行此動作,這是您設定為 PathEffect 屬性之 類別的SKPaint實例SKPathEffect。 您可以使用 所 SKPathEffect定義的其中一個靜態建立方法,建立路徑效果(或結合路徑效果)。 (SKPathEffect是 SkiaSharp 支援的六個效果之一;其他效果則描述於 SkiaSharp 效果一節中。

若要繪製虛線或虛線,您可以使用 SKPathEffect.CreateDash 靜態方法。 有兩個自變數:第一個是值陣列 float ,指出點和虛線的長度,以及兩者之間空格的長度。 這個陣列必須有偶數個元素,而且至少應該有兩個元素。 (陣列中可以有零個專案,但會產生實線。如果有兩個元素,第一個是點或虛線的長度,第二個是下一個點或虛線之前的間距長度。 如果有兩個以上的元素,則其順序如下:虛線長度、間距長度、虛線長度、間距長度等等。

一般而言,您會想要讓虛線和間距長度成為筆劃寬度的倍數。 例如,如果筆劃寬度為 10 像素,則陣列 { 10, 10 } 會繪製虛線,其中點和間距與筆劃粗細的長度相同。

不過, StrokeCap 對象的設定 SKPaint 也會影響這些點和虛線。 如您所見,這會影響此陣列的元素。

虛線和虛線會在 [點] 和 [虛線] 頁面上示範DotsAndDashesPage.xaml 檔案會具現化兩Picker個檢視,一個可讓您選取筆劃上限,第二個用來選取虛線數位:

<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.DotsAndDashesPage"
             Title="Dots and Dashes">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Picker x:Name="strokeCapPicker"
                Title="Stroke Cap"
                Grid.Row="0"
                Grid.Column="0"
                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>

        <Picker x:Name="dashArrayPicker"
                Title="Dash Array"
                Grid.Row="0"
                Grid.Column="1"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type x:String}">
                    <x:String>10, 10</x:String>
                    <x:String>30, 10</x:String>
                    <x:String>10, 10, 30, 10</x:String>
                    <x:String>0, 20</x:String>
                    <x:String>20, 20</x:String>
                    <x:String>0, 20, 20, 20</x:String>
                </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>

中的 dashArrayPicker 前三個專案假設筆劃寬度為10圖元。 { 10, 10 } 陣列適用於虛線,{ 30, 10 } 適用於虛線,而 { 10, 10, 30, 10 } 適用於虛線和虛線。 (其他三項將很快討論。

程式 DotsAndDashesPage 代碼後置檔案包含 PaintSurface 事件處理程式和幾個可存取檢視的 Picker 協助程式例程:

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

    canvas.Clear();

    SKPaint paint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Blue,
        StrokeWidth = 10,
        StrokeCap = (SKStrokeCap)strokeCapPicker.SelectedItem,
        PathEffect = SKPathEffect.CreateDash(GetPickerArray(dashArrayPicker), 20)
    };

    SKPath path = new SKPath();
    path.MoveTo(0.2f * info.Width, 0.2f * info.Height);
    path.LineTo(0.8f * info.Width, 0.8f * info.Height);
    path.LineTo(0.2f * info.Width, 0.8f * info.Height);
    path.LineTo(0.8f * info.Width, 0.2f * info.Height);

    canvas.DrawPath(path, paint);
}

float[] GetPickerArray(Picker picker)
{
    if (picker.SelectedIndex == -1)
    {
        return new float[0];
    }

    string str = (string)picker.SelectedItem;
    string[] strs = str.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
    float[] array = new float[strs.Length];

    for (int i = 0; i < strs.Length; i++)
    {
        array[i] = Convert.ToSingle(strs[i]);
    }
    return array;
}

在下列螢幕快照中,最左邊的 iOS 畫面會顯示虛線:

Dots 和 Dashes 頁面的三重螢幕快照

不過,Android 畫面也應該使用數位 { 10, 10 } 來顯示虛線,但線條是實心的。 發生什麼事? 問題是Android畫面也有筆劃上限設定 Square。 這會將所有虛線延伸一半的筆劃寬度,導致它們填滿間距。

若要在使用 或Round的筆劃上限Square時解決此問題,您必須將數位中的虛線長度減少筆劃長度(有時導致虛線長度為 0),並增加筆劃長度的間距長度。 這是 XAML 檔案中 Picker 最後三個破折號陣列的計算方式:

  • { 10, 10 } 會變成虛線的 { 0, 20 }
  • { 30, 10 } 會變成 { 20, 20 } 代表虛線
  • { 10, 10, 30, 10 } 會變成 { 0, 20, 20, 20} 代表虛線和虛線

UWP 畫面會顯示的筆劃上限 Round虛線和虛線。 筆 Round 觸上限通常會以粗線呈現點和虛線的最佳外觀。

到目前為止,尚未提及 方法的第二個參數 SKPathEffect.CreateDash 。 這個參數會命名 phase 為 ,其是指線條開頭的點與虛線圖樣內的位移。 例如,如果虛線陣列是 { 10, 10 } 且 phase 為 10,則線條會以間距而不是點開頭。

參數的 phase 一個有趣的應用程式是在動畫中。 [動畫螺旋] 頁面類似於 Archimedean Spiral 頁面,不同之處在於 類別AnimatedSpiralPage會使用 Xamarin.FormsDevice.Timer 方法以phase動畫顯示 參數:

public class AnimatedSpiralPage : ContentPage
{
    const double cycleTime = 250;       // in milliseconds

    SKCanvasView canvasView;
    Stopwatch stopwatch = new Stopwatch();
    bool pageIsActive;
    float dashPhase;

    public AnimatedSpiralPage()
    {
        Title = "Animated Spiral";

        canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        pageIsActive = true;
        stopwatch.Start();

        Device.StartTimer(TimeSpan.FromMilliseconds(33), () =>
        {
            double t = stopwatch.Elapsed.TotalMilliseconds % cycleTime / cycleTime;
            dashPhase = (float)(10 * t);
            canvasView.InvalidateSurface();

            if (!pageIsActive)
            {
                stopwatch.Stop();
            }

            return pageIsActive;
        });
    }
    ···  
}

當然,您必須實際執行程式,才能看到動畫:

[動畫螺旋式] 頁面的三重螢幕快照