Pontos e traços no SkiaSharp
Domine os meandros do desenho de linhas pontilhadas e tracejadas em SkiaSharp
SkiaSharp permite desenhar linhas que não são sólidas, mas são compostas de pontos e traços:
Você faz isso com um efeito de caminho, que é uma instância da SKPathEffect
classe que você definiu para a PathEffect
propriedade de SKPaint
. Você pode criar um efeito de caminho (ou combinar efeitos de caminho) usando um dos métodos de criação estática definidos pelo SKPathEffect
. SKPathEffect
( é um dos seis efeitos suportados pelo SkiaSharp; os outros são descritos na seção SkiaSharp Effect.)
Para desenhar linhas pontilhadas ou tracejadas, use o SKPathEffect.CreateDash
método estático. Há dois argumentos: este primeiro é uma matriz de float
valores que indicam os comprimentos dos pontos e traços e o comprimento dos espaços entre eles. Essa matriz deve ter um número par de elementos e deve haver pelo menos dois elementos. (Pode haver zero elementos na matriz, mas isso resulta em uma linha sólida.) Se houver dois elementos, o primeiro é o comprimento de um ponto ou traço, e o segundo é o comprimento da lacuna antes do próximo ponto ou traço. Se houver mais de dois elementos, eles estão nesta ordem: comprimento do traço, comprimento do intervalo, comprimento do traço, comprimento do intervalo e assim por diante.
Geralmente, convém tornar os comprimentos de traço e intervalo um múltiplo da largura do traçado. Se a largura do traçado for de 10 pixels, por exemplo, a matriz { 10, 10 } desenhará uma linha pontilhada onde os pontos e lacunas têm o mesmo comprimento que a espessura do traçado.
No entanto, a StrokeCap
SKPaint
configuração do objeto também afeta esses pontos e traços. Como você verá em breve, isso tem um impacto nos elementos dessa matriz.
Linhas pontilhadas e tracejadas são demonstradas na página Pontos e traços . O arquivo DotsAndDashesPage.xaml instancia dois Picker
modos de exibição, um para permitir que você selecione uma tampa de traçado e o segundo para selecionar uma matriz de traço:
<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>
Os três primeiros itens no dashArrayPicker
pressupõem que a largura do traçado é de 10 pixels. A matriz { 10, 10 } é para uma linha pontilhada, { 30, 10 } é para uma linha tracejada e { 10, 10, 30, 10 } é para uma linha dot-and-dash. (Os outros três serão discutidos em breve.)
O DotsAndDashesPage
arquivo code-behind contém o PaintSurface
manipulador de eventos e algumas rotinas auxiliares para acessar os Picker
modos de exibição:
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;
}
Nas capturas de tela a seguir, a tela do iOS na extrema esquerda mostra uma linha pontilhada:
No entanto, a tela do Android também deve mostrar uma linha pontilhada usando a matriz { 10, 10 }, mas em vez disso, a linha é sólida. O que aconteceu? O problema é que a tela do Android também tem uma configuração de stroke caps de Square
. Isso estende todos os traços pela metade da largura do traçado, fazendo com que eles preencham as lacunas.
Para contornar esse problema ao usar um limite de traçado de ou Round
, você deve diminuir os comprimentos de Square
traço na matriz pelo comprimento do traçado (às vezes resultando em um comprimento de traço de 0) e aumentar os comprimentos de intervalo pelo comprimento do traçado. É assim que as três matrizes de traço finais no Picker
arquivo XAML foram calculadas:
- { 10, 10 } torna-se { 0, 20 } para uma linha pontilhada
- { 30, 10 } torna-se { 20, 20 } para uma linha tracejada
- { 10, 10, 30, 10 } torna-se { 0, 20, 20, 20} para uma linha pontilhada e tracejada
A tela UWP mostra essa linha pontilhada e tracejada para um limite de traçado de Round
. A Round
tampa de traçado geralmente dá a melhor aparência de pontos e traços em linhas grossas.
Até o momento, nenhuma menção foi feita ao segundo parâmetro do SKPathEffect.CreateDash
método. Esse parâmetro é nomeado phase
e refere-se a um deslocamento dentro do padrão ponto-e-traço para o início da linha. Por exemplo, se a matriz de traço for { 10, 10 } e a phase
for 10, a linha começará com uma lacuna em vez de um ponto.
Uma aplicação interessante do phase
parâmetro é em uma animação. A página Espiral Animada é semelhante à página Espiral de Arquimedes , exceto que a AnimatedSpiralPage
classe anima o phase
parâmetro usando o Xamarin.FormsDevice.Timer
método:
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;
});
}
···
}
Claro, você terá que realmente executar o programa para ver a animação: