Линии и концы штрихов
Узнайте, как использовать SkiaSharp для рисования линий с различными крышками штрихов
В SkiaSharp отрисовка одной строки отличается от от отрисовки ряда подключенных прямых линий. Даже при рисовании отдельных линий, однако, часто необходимо дать линии определенной ширины штриха. По мере того как эти линии становятся более широкими, внешний вид концы линий также становится важным. Внешний вид конца линии называется крышкой штриха:
Для рисования отдельных строк определяет простой DrawLine
метод, SKCanvas
аргументы которого указывают начальные и конечные координаты строки с SKPaint
объектом:
canvas.DrawLine (x0, y0, x1, y1, paint);
По умолчанию StrokeWidth
свойство нового экземпляра SKPaint
объекта равно 0, которое имеет тот же эффект, что и значение 1 при отрисовке строки одного пикселя в толщине. Это выглядит очень тонко на устройствах с высоким разрешением, таких как телефоны, поэтому вы, вероятно, хотите задать StrokeWidth
большее значение. Но после начала рисования линий изменяемой толщины, которая вызывает другую проблему: как должны быть отрисованы начальные и концы этих толстых линий?
Внешний вид стартов и концы линий называется крышкой линии или, в Skia, штриховой крышкой. Слово "cap" в этом контексте относится к типу шляпы - то, что сидит в конце строки. Для свойства SKPaint
объекта задано StrokeCap
одно из следующих элементов SKStrokeCap
перечисления:
Butt
(значение по умолчанию)Square
Round
Это лучше всего иллюстрируется примером программы. Раздел SkiaSharp Lines и Paths примера программы начинается со страницы с заголовком caps на основе StrokeCapsPage
класса. На этой странице определяется PaintSurface
обработчик событий, который циклит по трем элементам SKStrokeCap
перечисления, отображая имя элемента перечисления и рисуя строку с помощью этой крышки штриха:
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;
}
}
Для каждого элемента SKStrokeCap
перечисления обработчик рисует две линии, один с толщиной штриха 50 пикселей, а другая линия, расположенная поверх толщины штриха двух пикселей. Эта вторая строка предназначена для иллюстрации геометрического начала и конца линии независимо от толщины линии и штриховой крышки:
Как видно, Square
Round
и крышки штрихов эффективно расширяют длину линии на половину ширины штриха в начале линии и снова в конце. Это расширение становится важным, когда необходимо определить размеры отрисованного графического объекта.
Класс SKCanvas
также включает другой метод для рисования нескольких строк, которые несколько своеобразны:
DrawPoints (SKPointMode mode, points, paint)
Параметр points
представляет собой массив значений SKPoint
и mode
является членом SKPointMode
перечисления, который содержит три элемента:
Points
отображение отдельных точекLines
подключение каждой пары точекPolygon
подключение всех последовательных точек
На странице "Несколько строк" показан этот метод. Файл MultipleLinesPage.xaml создает экземпляры двух Picker
представлений, которые позволяют выбрать элемент SKPointMode
перечисления и элемент SKStrokeCap
перечисления:
<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>
Обратите внимание, что объявления пространства имен SkiaSharp немного отличаются, так как SkiaSharp
пространство имен необходимо для ссылки на элементы SKPointMode
и SKStrokeCap
перечисления. Обработчик SelectedIndexChanged
обоих Picker
представлений просто делает объект недействительным SKCanvasView
:
void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
if (canvasView != null)
{
canvasView.InvalidateSurface();
}
}
Этот обработчик должен проверка для существования SKCanvasView
объекта, так как обработчик событий сначала вызывается, когда SelectedIndex
свойство Picker
объекта имеет значение 0 в XAML-файле и возникает до SKCanvasView
создания экземпляра.
Обработчик PaintSurface
получает два значения перечисления из представлений Picker
:
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);
}
На снимках экрана показаны различные Picker
варианты выбора:
I Телефон слева показывает, как SKPointMode.Points
член перечисления вызывает DrawPoints
отрисовку каждой точки в SKPoint
массиве в виде квадрата, если крышка Butt
строки илиSquare
. Круги отрисовываются, если ограничение строки равно Round
.
Снимок экрана с Android показывает результат SKPointMode.Lines
. Метод DrawPoints
рисует линию между каждой парой значений SKPoint
, используя указанную крышку строки в данном случае Round
.
Вместо этого SKPointMode.Polygon
линия рисуется между последовательными точками в массиве, но при внимательном просмотре вы увидите, что эти линии не подключены. Каждая из этих отдельных строк начинается и заканчивается указанным ограничением строки. Если выбрать Round
крышки, линии могут быть подключены, но они действительно не подключены.
Независимо от того, подключены ли линии, являются важным аспектом работы с графическими путями.