Líneas y extremos de trazo
Aprenda a usar SkiaSharp para dibujar líneas con diferentes tapas de trazo
En SkiaSharp, la representación de una sola línea es muy diferente de representar una serie de líneas rectas conectadas. Sin embargo, incluso cuando se dibujan líneas únicas, a menudo es necesario dar a las líneas un ancho de trazo determinado. A medida que estas líneas se vuelven más anchas, la apariencia de los extremos de las líneas también es importante. La apariencia del final de la línea se denomina límite de trazo:
Para dibujar líneas simples, SKCanvas
define un método simple DrawLine
cuyos argumentos indican las coordenadas inicial y final de la línea con un SKPaint
objeto :
canvas.DrawLine (x0, y0, x1, y1, paint);
De forma predeterminada, la StrokeWidth
propiedad de un objeto recién creado SKPaint
es 0, que tiene el mismo efecto que un valor de 1 en la representación de una línea de un píxel en grosor. Esto aparece muy fino en dispositivos de alta resolución, como teléfonos, por lo que probablemente querrá establecer en StrokeWidth
un valor mayor. Pero una vez que empiece a dibujar líneas de un grosor considerable, esto provoca otro problema: ¿Cómo deben representarse los inicios y extremos de estas líneas gruesas?
La apariencia de los inicios y extremos de las líneas se denomina extremo de línea o, en Skia, un extremo de trazo. La palabra "cap" en este contexto hace referencia a un tipo de sombrero, algo que se encuentra al final de la línea. La propiedad del SKPaint
objeto se establece StrokeCap
en uno de los siguientes miembros de la SKStrokeCap
enumeración:
Butt
(valor predeterminado)Square
Round
Se ilustran mejor con un programa de ejemplo. La sección Líneas y rutas de skiaSharp del programa SkiaSharpFormsDemos comienza con una página titulada Stroke Caps basada en la StrokeCapsPage
clase . En esta página se define un PaintSurface
controlador de eventos que recorre en bucle los tres miembros de la SKStrokeCap
enumeración, mostrando el nombre del miembro de enumeración y dibujando una línea con ese límite de trazo:
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;
}
}
Para cada miembro de la SKStrokeCap
enumeración, el controlador dibuja dos líneas, una con un grosor de trazo de 50 píxeles y otra línea situada en la parte superior con un grosor de trazo de dos píxeles. Esta segunda línea está pensada para ilustrar el inicio geométrico y el final de la línea independientemente del grosor de la línea y un extremo de trazo:
Como puede ver, los Square
límites de trazo y Round
extienden eficazmente la longitud de la línea por la mitad del ancho del trazo al principio de la línea y de nuevo al final. Esta extensión es importante cuando es necesario determinar las dimensiones de un objeto gráfico representado.
La SKCanvas
clase también incluye otro método para dibujar varias líneas que es algo peculiar:
DrawPoints (SKPointMode mode, points, paint)
El points
parámetro es una matriz de SKPoint
valores y mode
es miembro de la SKPointMode
enumeración , que tiene tres miembros:
Points
para representar los puntos individualesLines
para conectar cada par de puntosPolygon
para conectar todos los puntos consecutivos
En la página Varias líneas se muestra este método. El archivo MultipleLinesPage.xaml crea una instancia de dos Picker
vistas que permiten seleccionar un miembro de la SKPointMode
enumeración y un miembro de la SKStrokeCap
enumeración:
<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>
Observe que las declaraciones de espacio de nombres SkiaSharp son un poco diferentes porque el SkiaSharp
espacio de nombres es necesario para hacer referencia a los miembros de las SKPointMode
enumeraciones y SKStrokeCap
. El SelectedIndexChanged
controlador de ambas Picker
vistas simplemente invalida el SKCanvasView
objeto :
void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
if (canvasView != null)
{
canvasView.InvalidateSurface();
}
}
Este controlador debe comprobar la existencia del SKCanvasView
objeto porque primero se llama al controlador de eventos cuando la SelectedIndex
propiedad de Picker
se establece en 0 en el archivo XAML y se produce antes SKCanvasView
de que se haya creado una instancia de .
El PaintSurface
controlador obtiene los dos valores de enumeración de las Picker
vistas:
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);
}
Las capturas de pantalla muestran una variedad de Picker
selecciones:
El iPhone de la izquierda muestra cómo el SKPointMode.Points
miembro de enumeración hace DrawPoints
que cada uno de los puntos de la SKPoint
matriz sea un cuadrado si el límite de línea es Butt
o Square
. Los círculos se representan si el límite de línea es Round
.
En la captura de pantalla de Android se muestra el resultado de SKPointMode.Lines
. El DrawPoints
método dibuja una línea entre cada par de valores, utilizando el límite de SKPoint
línea especificado, en este caso Round
.
Cuando en su lugar usa SKPointMode.Polygon
, se dibuja una línea entre los puntos sucesivos de la matriz, pero si observa muy detenidamente, verá que estas líneas no están conectadas. Cada una de estas líneas independientes comienza y termina con el límite de línea especificado. Si selecciona los Round
límites, es posible que parezca que las líneas están conectadas, pero realmente no están conectadas.
Tanto si las líneas están conectadas como si no están conectadas es un aspecto crucial de trabajar con rutas de gráficos.