Пиксели и аппаратно-независимые единицы
Изучение различий между координатами и Xamarin.Forms координатами SkiaSharp
В этой статье рассматриваются различия в системе координат, используемой в SkiaSharp и Xamarin.Forms. Вы можете получить сведения для преобразования между двумя системами координат, а также рисования графики, заполняющей определенную область:
Если вы в течение некоторого времени программировали Xamarin.Forms , возможно, у вас есть ощущение Xamarin.Forms координат и размеров. Круги, нарисованные в двух предыдущих статьях, могут показаться немного маленькими для вас.
Эти круги небольшие по сравнению с Xamarin.Forms размерами. По умолчанию SkiaSharp рисует единицы пикселей, а Xamarin.Forms базы координаты и размеры на устройстве независимо от устройства единиц, установленных базовой платформой. (Дополнительные сведения о системе Xamarin.Forms координат можно найти в главе 5. Работа с размерами книги "Создание мобильных приложений с Xamarin.Formsпомощью .)
Страница в примере программы Surface Size использует текстовые выходные данные SkiaSharp для отображения размера поверхности отображения из трех разных источников:
- Обычные Xamarin.Forms
Width
иHeight
свойстваSKCanvasView
объекта. - Свойство
CanvasSize
объектаSKCanvasView
. Size
СвойствоSKImageInfo
значения, которое соответствуетWidth
свойствам,Height
используемым на двух предыдущих страницах.
В SurfaceSizePage
классе показано, как отобразить эти значения. Конструктор сохраняет SKCanvasView
объект в виде поля, чтобы его можно было получить в обработчике PaintSurface
событий:
SKCanvasView canvasView;
public SurfaceSizePage()
{
Title = "Surface Size";
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
SKCanvas
включает шесть различных DrawText
методов, но этот DrawText
метод является самым простым:
public void DrawText (String text, Single x, Single y, SKPaint paint)
Вы указываете текстовую строку, координаты X и Y, где начинается текст, и SKPaint
объект. Координата X указывает расположение левой стороны текста, но следите за тем, чтобы координата Y указывала позицию базового плана текста. Если вы когда-либо написали вручную на листе бумаги, базовый план — это линия, на которой сидеть символы, и под которыми нисходящие (например, на буквах g, p, q и y) убыть.
Объект SKPaint
позволяет указать цвет текста, семейство шрифтов и размер текста. По умолчанию TextSize
свойство имеет значение 12, что приводит к крошечному тексту на устройствах с высоким разрешением, таких как телефоны. В чем-либо, кроме самых простых приложений, вам также потребуется некоторая информация о размере отображаемого текста. Класс SKPaint
определяет FontMetrics
свойство и несколько MeasureText
методов, FontSpacing
но для менее необычных потребностей свойство предоставляет рекомендуемое значение для интервала последовательных строк текста.
PaintSurface
Следующий обработчик создает SKPaint
объект для TextSize
40 пикселей, который является требуемой вертикальной высотой текста от верхней части возрастания до нижней части спуска. Значение FontSpacing
, возвращаемое SKPaint
объектом, немного больше, чем это, около 47 пикселей.
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKPaint paint = new SKPaint
{
Color = SKColors.Black,
TextSize = 40
};
float fontSpacing = paint.FontSpacing;
float x = 20; // left margin
float y = fontSpacing; // first baseline
float indent = 100;
canvas.DrawText("SKCanvasView Height and Width:", x, y, paint);
y += fontSpacing;
canvas.DrawText(String.Format("{0:F2} x {1:F2}",
canvasView.Width, canvasView.Height),
x + indent, y, paint);
y += fontSpacing * 2;
canvas.DrawText("SKCanvasView CanvasSize:", x, y, paint);
y += fontSpacing;
canvas.DrawText(canvasView.CanvasSize.ToString(), x + indent, y, paint);
y += fontSpacing * 2;
canvas.DrawText("SKImageInfo Size:", x, y, paint);
y += fontSpacing;
canvas.DrawText(info.Size.ToString(), x + indent, y, paint);
}
Метод начинает первую строку текста с координатой X 20 (для небольшого поля слева) и координатой fontSpacing
Y, которая немного превышает то, что необходимо для отображения полной высоты первой строки текста в верхней части поверхности отображения. После каждого вызова DrawText
координата Y увеличивается на один или два приращения fontSpacing
.
Вот работающая программа:
Как видно, CanvasSize
свойство и Size
свойство SKCanvasView
SKImageInfo
значения согласованы в отчетах о измерениях пикселей. Свойства Height
являются Width
Xamarin.Forms свойствами и сообщают о размере представления в независимых SKCanvasView
от устройства единицах, определенных платформой.
Семь симуляторов iOS слева имеют два пикселя на устройство независимо от устройства, и Android Nexus 5 в центре имеет три пикселя на единицу. Вот почему простой круг, показанный ранее, имеет разные размеры на разных платформах.
Если вы предпочитаете полностью работать в единицах, независимых от устройств, это можно сделать, задав IgnorePixelScaling
для свойства объекта true
SKCanvasView
значение . Однако результаты могут не понравиться. SkiaSharp отрисовывает графику на меньшей поверхности устройства с размером пикселя, равным размеру представления в независимых от устройства единицах. (Например, SkiaSharp будет использовать поверхность дисплея 360 x 512 пикселей на Nexus 5.) Затем он масштабирует это изображение в размере, что приводит к заметным растровым изображениям jaggies.
Чтобы обеспечить одинаковое разрешение изображений, лучшее решение заключается в написании собственных простых функций для преобразования между двумя системами координат.
DrawCircle
Помимо метода, также определяет два DrawOval
метода, SKCanvas
которые рисуют многоточие. Многоточие определяется двумя радиями, а не одним радиусом. Они называются основным радиусом и дополнительным радиусом. Метод DrawOval
рисует многоточие с двумя радиями параллельно с осями X и Y. (Если вам нужно нарисовать многоточие с осями, не параллельными осям X и Y, можно использовать преобразование поворота, как описано в статье Преобразование поворота или графический путь, как описано в статье "Три способа рисования дуги". Эта перегрузка DrawOval
метода называет два параметра rx
радии и ry
указывает, что они параллельны осям X и Y:
public void DrawOval (Single cx, Single cy, Single rx, Single ry, SKPaint paint)
Можно ли нарисовать многоточие, заполняющее поверхность дисплея? На странице Ellipse Fill показано, как. Обработчик PaintSurface
событий в классе EllipseFillPage.xaml.cs вычитает половину ширины штриха из xRadius
yRadius
и значений, чтобы соответствовать всему многоточию и ее контуру в области отображения:
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
float strokeWidth = 50;
float xRadius = (info.Width - strokeWidth) / 2;
float yRadius = (info.Height - strokeWidth) / 2;
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Blue,
StrokeWidth = strokeWidth
};
canvas.DrawOval(info.Width / 2, info.Height / 2, xRadius, yRadius, paint);
}
Здесь выполняется:
Другой DrawOval
метод имеет SKRect
аргумент, который представляет собой прямоугольник, определенный с точки зрения координат X и Y в левом верхнем углу и правом нижнем углу. Овал заполняет прямоугольник, который предполагает, что его можно использовать на странице Ellipse Fill , как показано ниже:
SKRect rect = new SKRect(0, 0, info.Width, info.Height);
canvas.DrawOval(rect, paint);
Тем не менее, это усечение всех краев контура эллипса на четырех сторонах. Чтобы сделать эту работу правильной SKRect
, необходимо настроить все аргументы конструктора strokeWidth
:
SKRect rect = new SKRect(strokeWidth / 2,
strokeWidth / 2,
info.Width - strokeWidth / 2,
info.Height - strokeWidth / 2);
canvas.DrawOval(rect, paint);