Punti e trattini in SkiaSharp
Padroneggia le complessità del disegno di linee tratteggiate e tratteggiate in SkiaSharp
SkiaSharp consente di disegnare linee non solide, ma composte da punti e trattini:
Questa operazione viene eseguita con un effetto di percorso, ovvero un'istanza della SKPathEffect
classe impostata sulla PathEffect
proprietà di SKPaint
. È possibile creare un effetto di percorso (o combinare gli effetti del percorso) usando uno dei metodi di creazione statici definiti da SKPathEffect
. (SKPathEffect
è uno dei sei effetti supportati da SkiaSharp; gli altri sono descritti nella sezione Effetto SkiaSharp.
Per disegnare linee tratteggiate o tratteggiate, utilizzare il SKPathEffect.CreateDash
metodo statico. Esistono due argomenti: questo primo è una matrice di float
valori che indicano le lunghezze dei punti e dei trattini e la lunghezza degli spazi tra di essi. Questa matrice deve avere un numero pari di elementi e deve essere presente almeno due elementi. Nella matrice possono essere presenti zero elementi, ma ciò comporta una linea continua. Se sono presenti due elementi, il primo è la lunghezza di un punto o un trattino e il secondo è la lunghezza del gap prima del punto o trattino successivo. Se sono presenti più di due elementi, sono in questo ordine: lunghezza trattino, lunghezza distanza, lunghezza trattino, lunghezza del trattino, lunghezza distanza e così via.
In genere, è consigliabile fare in modo che il trattino e la lunghezza del gap sia un multiplo della larghezza del tratto. Se la larghezza del tratto è 10 pixel, ad esempio, la matrice { 10, 10 } disegnerà una linea punteggiata in cui i punti e gli spazi vuoti sono la stessa lunghezza dello spessore del tratto.
Tuttavia, l'impostazione StrokeCap
dell'oggetto SKPaint
influisce anche su questi punti e trattini. Come si vedrà a breve, questo ha un impatto sugli elementi di questa matrice.
Le linee tratteggiate e tratteggiate vengono illustrate nella pagina Punti e trattini . Il file DotsAndDashesPage.xaml crea un'istanza di due Picker
visualizzazioni, una per consentire di selezionare un limite di tratto e la seconda per selezionare una matrice trattino:
<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 nell'oggetto dashArrayPicker
presuppongono che la larghezza del tratto sia di 10 pixel. La matrice { 10, 10 } è per una linea punteggiata, { 30, 10 } è per una linea tratteggiata e { 10, 10, 30, 10 } è per una linea punto e trattino. Gli altri tre verranno discussi a breve.
Il DotsAndDashesPage
file code-behind contiene il PaintSurface
gestore eventi e un paio di routine helper per l'accesso alle Picker
visualizzazioni:
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;
}
Negli screenshot seguenti la schermata iOS a sinistra mostra una linea tratteggiata:
Tuttavia, la schermata Android dovrebbe anche mostrare una linea punteggiata usando la matrice { 10, 10 } ma invece la linea è continua. Che cosa è successo? Il problema è che la schermata Android ha anche un'impostazione di limite di tratto di Square
. Questo estende tutti i trattini per metà della larghezza del tratto, causando il riempimento delle lacune.
Per aggirare questo problema quando si usa un limite di tratto di Square
o Round
, è necessario ridurre le lunghezze del trattino nella matrice in base alla lunghezza del tratto (a volte determinando una lunghezza del trattino pari a 0) e aumentare la lunghezza del gap in base alla lunghezza del tratto. Ecco come sono state calcolate le tre matrici tratteggiate finali nel Picker
file XAML:
- { 10, 10 } diventa { 0, 20 } per una linea tratteggiata
- { 30, 10 } diventa { 20, 20 } per una linea tratteggiata
- { 10, 10, 30, 10 } diventa { 0, 20, 20, 20} per una linea tratteggiata e tratteggiata
La schermata UWP mostra che la linea tratteggiata e tratteggiata per un limite di tratto di Round
. L'estremità Round
del tratto spesso dà l'aspetto migliore di punti e trattini in linee spesse.
Finora non è stata fatta alcuna menzione del secondo parametro per il SKPathEffect.CreateDash
metodo . Questo parametro è denominato phase
e fa riferimento a un offset all'interno del motivo punto e trattino per l'inizio della linea. Ad esempio, se la matrice di trattini è { 10, 10 } e phase
è 10, la riga inizia con una distanza anziché un punto.
Un'applicazione interessante del phase
parametro è in un'animazione. La pagina Spirale animata è simile alla pagina Spiralean Archimedean, ad eccezione del fatto che la AnimatedSpiralPage
classe anima il phase
parametro usando il Xamarin.FormsDevice.Timer
metodo :
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, dovrai eseguire effettivamente il programma per visualizzare l'animazione: