Punti e trattini in SkiaSharpDots and Dashes in SkiaSharp

Scaricare l'esempio scaricare l'esempioDownload Sample Download the sample

Master le complicazioni del disegno di linee con tratteggiate o in SkiaSharpMaster the intricacies of drawing dotted and dashed lines in SkiaSharp

SkiaSharp consente di disegnare le righe che non sono affidabili ma che invece sono costituiti da punti e trattini:SkiaSharp lets you draw lines that are not solid but instead are composed of dots and dashes:

Usando un effetto del percorso, che è un'istanza del SKPathEffect classe che è impostato sulla PathEffect proprietà di SKPaint.You do this with a path effect, which is an instance of the SKPathEffect class that you set to the PathEffect property of SKPaint. È possibile creare un percorso di effetto (o combinare percorso effetti) utilizzando uno dei metodi di creazione statici definiti da SKPathEffect.You can create a path effect (or combine path effects) using one of the static creation methods defined by SKPathEffect. (SKPathEffect è uno dei sei gli effetti supportato da SkiaSharp; gli altri sono descritti nella sezione effetto SkiaSharp.)(SKPathEffect is one of six effects supported by SkiaSharp; the others are described in the section SkiaSharp Effect.)

Per disegnare linee tratteggiate o punteggiate, si utilizza il SKPathEffect.CreateDash metodo statico.To draw dotted or dashed lines, you use the SKPathEffect.CreateDash static method. Esistono due argomenti: Questa prima è una matrice di float valori che indicano le lunghezze dei punti e dei trattini e la lunghezza degli spazi tra di essi.There are two arguments: This first is an array of float values that indicate the lengths of the dots and dashes and the length of the spaces between them. Questa matrice deve avere un numero pari di elementi e devono essere presenti almeno due elementi.This array must have an even number of elements, and there should be at least two elements. (Può essere zero elementi nella matrice, ma che i risultati in una linea continua.) Se sono presenti due elementi, la prima è la lunghezza di un punto o trattino e il secondo è la lunghezza del gap prima il successivo punto o trattino.(There can be zero elements in the array but that results in a solid line.) If there are two elements, the first is the length of a dot or dash, and the second is the length of the gap before the next dot or dash. Se sono presenti più di due elementi, quindi sono nell'ordine indicato: trattino di lunghezza, durata dell'intervallo, lunghezza del trattino, durata dell'intervallo e così via.If there are more than two elements, then they are in this order: dash length, gap length, dash length, gap length, and so on.

In generale, è opportuno apportare le lunghezze dash e gap un multiplo dello spessore del tratto.Generally, you'll want to make the dash and gap lengths a multiple of the stroke width. Se lo spessore del tratto è di 10 pixel, ad esempio, quindi la matrice {10, 10} verrà disegnare una linea punteggiata in cui i punti e spazi vuoti sono della stessa lunghezza come lo spessore del tratto.If the stroke width is 10 pixels, for example, then the array { 10, 10 } will draw a dotted line where the dots and gaps are the same length as the stroke thickness.

Tuttavia, il StrokeCap impostazione del SKPaint oggetto interessa anche questi punti e trattini.However, the StrokeCap setting of the SKPaint object also affects these dots and dashes. Come si vedrà a breve, che ha un impatto sugli elementi di questa matrice.As you'll see shortly, that has an impact on the elements of this array.

Con punti e vengono illustrate le linee tratteggiate nella da punti e trattini pagina.Dotted and dashed lines are demonstrated on the Dots and Dashes page. Il DotsAndDashesPage.xaml un'istanza di file due Picker Visualizza, uno per cui è possibile selezionare un'estremità della traccia e il secondo per selezionare un array di dash:The DotsAndDashesPage.xaml file instantiates two Picker views, one for letting you select a stroke cap and the second to select a dash array:

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

I primi tre elementi di dashArrayPicker si presuppone che lo spessore del tratto sia 10 pixel.The first three items in the dashArrayPicker assume that the stroke width is 10 pixels. La {10, 10} array si trovi per una linea punteggiata, {30, 10} è per una linea tratteggiata e {10, 10, 30, 10} per una riga di punto e dash.The { 10, 10 } array is for a dotted line, { 30, 10 } is for a dashed line, and { 10, 10, 30, 10 } is for a dot-and-dash line. (Gli altri tre verranno discussa tra breve.)(The other three will be discussed shortly.)

Il DotsAndDashesPage contiene file code-behind il PaintSurface gestore dell'evento e un paio di routine di supporto per l'accesso al Picker viste:The DotsAndDashesPage code-behind file contains the PaintSurface event handler and a couple of helper routines for accessing the Picker views:

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

Nelle schermate seguenti, la schermata iOS all'estrema sinistra mostra una linea punteggiata:In the following screenshots, the iOS screen on the far left shows a dotted line:

Tuttavia, lo schermo Android anche dovrebbe per visualizzare una linea punteggiata utilizzando la matrice {10, 10} ma è invece a tinta unita con la riga.However, the Android screen is also supposed to show a dotted line using the array { 10, 10 } but instead the line is solid. Cosa è successo?What happened? Il problema è che lo schermo Android include anche un'impostazione di criteri di autorizzazione connessioni tratto di Square.The problem is that the Android screen also has a stroke caps setting of Square. Estende tutti i trattini per metà della larghezza di tratto, comportando riempire i gap.This extends all the dashes by half the stroke width, causing them to fill up the gaps.

Per evitare questo problema quando si usa un'estremità del tratto del Square o Round, è necessario ridurre le lunghezze di trattino nella matrice per la lunghezza di tratto (talvolta risultante in una lunghezza di tratteggio pari a 0) e aumentare le lunghezze di gap per la lunghezza di tratto.To get around this problem when using a stroke cap of Square or Round, you must decrease the dash lengths in the array by the stroke length (sometimes resulting in a dash length of 0), and increase the gap lengths by the stroke length. Si tratta di come i tre finali dash matrici nel Picker nel file XAML sono state calcolate:This is how the final three dash arrays in the Picker in the XAML file were calculated:

  • {10, 10} diventa {0, 20} per una linea punteggiata{ 10, 10 } becomes { 0, 20 } for a dotted line
  • {30, 10} diventa {20, 20} per una linea tratteggiata{ 30, 10 } becomes { 20, 20 } for a dashed line
  • {10, 10, 30, 10} diventa {0, 20, 20, 20} per una riga con tratteggiata o{ 10, 10, 30, 10 } becomes { 0, 20, 20, 20} for a dotted and dashed line

Limitare il Mostra schermata UWP che da punti e linee tratteggiate line per un tratto di Round.The UWP screen shows that dotted and dashed line for a stroke cap of Round. Il Round nelle righe spesse estremità della traccia offre spesso l'aspetto migliore di punti e trattini.The Round stroke cap often gives the best appearance of dots and dashes in thick lines.

Finora non è diventato alcun accenno del secondo parametro per il SKPathEffect.CreateDash (metodo).So far no mention has been made of the second parameter to the SKPathEffect.CreateDash method. Questo parametro è denominato phase e fa riferimento a un offset all'interno del criterio trattino e punto per l'inizio della riga.This parameter is named phase and it refers to an offset within the dot-and-dash pattern for the beginning of the line. Ad esempio, se la matrice dash è {10, 10} che phase è 10, quindi la riga inizia con uno spazio vuoto anziché a un punto.For example, if the dash array is { 10, 10 } and the phase is 10, then the line begins with a gap rather than a dot.

Un'interessante applicazione dei phase parametro è un'animazione.One interesting application of the phase parameter is in an animation. Il animato spirale pagina è simile al Archimedean spirale pagina con la differenza che il AnimatedSpiralPage classe aggiunge un'animazione il phase parametro usando il Xamarin. Forms Device.Timer metodo:The Animated Spiral page is similar to the Archimedean Spiral page, except that the AnimatedSpiralPage class animates the phase parameter using the Xamarin.Forms Device.Timer method:

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

Naturalmente, è possibile eseguire effettivamente il programma per verificare l'animazione:Of course, you'll have to actually run the program to see the animation: