Преобразование переноса
Узнайте, как использовать преобразование перевода для смены графики SkiaSharp
Самый простой тип преобразования в SkiaSharp — преобразование перевода или перевода . Это преобразование сдвигает графические объекты в горизонтальных и вертикальных направлениях. В смысле перевод является самым ненужным преобразованием, так как обычно вы можете добиться того же эффекта, просто изменив координаты, которые вы используете в функции рисования. Однако при отрисовке пути все координаты инкапсулируются в пути, поэтому гораздо проще применить преобразование перевода для перемещения всего пути.
Перевод также полезен для анимации и для простых текстовых эффектов:
Метод Translate
имеет SKCanvas
два параметра, которые приводят к перемещению графических объектов по горизонтали и по вертикали:
public void Translate (Single dx, Single dy)
Эти аргументы могут быть отрицательными. Второй Translate
метод объединяет два значения перевода в одном SKPoint
значении:
public void Translate (SKPoint point)
На странице "Накопленный перевод" примера программы показано, что несколько вызовов Translate
метода являются накопительными. Класс AccumulatedTranslatePage
отображает 20 версий одного прямоугольника, каждый из которых смещается от предыдущего прямоугольника достаточно, чтобы они растягивали по диагонали. PaintSurface
Вот обработчик событий:
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint strokePaint = new SKPaint())
{
strokePaint.Color = SKColors.Black;
strokePaint.Style = SKPaintStyle.Stroke;
strokePaint.StrokeWidth = 3;
int rectangleCount = 20;
SKRect rect = new SKRect(0, 0, 250, 250);
float xTranslate = (info.Width - rect.Width) / (rectangleCount - 1);
float yTranslate = (info.Height - rect.Height) / (rectangleCount - 1);
for (int i = 0; i < rectangleCount; i++)
{
canvas.DrawRect(rect, strokePaint);
canvas.Translate(xTranslate, yTranslate);
}
}
}
Последовательные прямоугольники усложняют страницу:
Если накопленные факторы перевода имеют и dx
dy
, а точка, указанная в функции рисования (x
, y
), то графический объект отображается в точке (x'
, y'
где):
x ' = x + dx
y' = y + dy
Эти формулы называются формулами преобразования для перевода. Значения dx
по умолчанию для dy
нового SKCanvas
— 0.
Обычно преобразование перевода используется для эффектов тени и аналогичных методов, как демонстрируется на странице "Перевод текстовых эффектов ". Ниже приведена соответствующая часть обработчика PaintSurface
в TranslateTextEffectsPage
классе:
float textSize = 150;
using (SKPaint textPaint = new SKPaint())
{
textPaint.Style = SKPaintStyle.Fill;
textPaint.TextSize = textSize;
textPaint.FakeBoldText = true;
float x = 10;
float y = textSize;
// Shadow
canvas.Translate(10, 10);
textPaint.Color = SKColors.Black;
canvas.DrawText("SHADOW", x, y, textPaint);
canvas.Translate(-10, -10);
textPaint.Color = SKColors.Pink;
canvas.DrawText("SHADOW", x, y, textPaint);
y += 2 * textSize;
// Engrave
canvas.Translate(-5, -5);
textPaint.Color = SKColors.Black;
canvas.DrawText("ENGRAVE", x, y, textPaint);
canvas.ResetMatrix();
textPaint.Color = SKColors.White;
canvas.DrawText("ENGRAVE", x, y, textPaint);
y += 2 * textSize;
// Emboss
canvas.Save();
canvas.Translate(5, 5);
textPaint.Color = SKColors.Black;
canvas.DrawText("EMBOSS", x, y, textPaint);
canvas.Restore();
textPaint.Color = SKColors.White;
canvas.DrawText("EMBOSS", x, y, textPaint);
}
В каждом из трех примеров Translate
вызывается отображение текста для смещения текста из расположения, заданного x
переменными.y
Затем текст снова отображается в другом цвете без эффекта перевода:
Каждый из трех примеров показывает другой способ отрицания Translate
вызова:
Первый пример просто вызывает Translate
снова, но с отрицательными значениями. Translate
Так как вызовы являются накопительными, эта последовательность вызовов просто восстанавливает общее преобразование значений по умолчанию нулю.
Второй пример вызовов ResetMatrix
. Это приводит к тому, что все преобразования возвращаются в состояние по умолчанию.
Третий пример сохраняет состояние SKCanvas
объекта с вызовом Save
, а затем восстанавливает состояние с вызовом Restore
. Это самый универсальный способ управления преобразованиями для ряда операций рисования. Эти Save
функции и Restore
вызовы, такие как стек: можно Save
вызывать несколько раз, а затем вызывать Restore
обратную последовательность, чтобы вернуться к предыдущим состояниям. Метод Save
возвращает целое число, и вы можете передать это целое число для RestoreToCount
эффективного вызова Restore
несколько раз. Свойство SaveCount
возвращает количество состояний, сохраненных в стеке.
Вы также можете использовать SKAutoCanvasRestore
класс для восстановления состояния холста. Конструктор этого класса должен вызываться в using
операторе. Состояние холста автоматически восстанавливается в конце using
блока.
Однако вам не нужно беспокоиться о преобразованиях, передаваемых с одного вызова обработчика PaintSurface
на следующий. Каждый новый вызов для PaintSurface
доставки нового SKCanvas
объекта с преобразованиями по умолчанию.
Другое частое использование Translate
преобразования заключается в отрисовке визуального объекта, который изначально был создан с помощью координат, удобных для рисования. Например, может потребоваться указать координаты для аналоговых часов с центром в точке (0, 0). Затем можно использовать преобразования для отображения часов, в которых вы хотите. Этот метод демонстрируется на странице [Массив Hendecagram]. Класс HendecagramArrayPage
начинается с создания SKPath
объекта для 11-конечной звезды. Объект HendecagramPath
определяется как общедоступный, статический и доступный только для чтения, чтобы он был доступен из других демонстрационных программ. Он создается в статическом конструкторе:
public class HendecagramArrayPage : ContentPage
{
...
public static readonly SKPath HendecagramPath;
static HendecagramArrayPage()
{
// Create 11-pointed star
HendecagramPath = new SKPath();
for (int i = 0; i < 11; i++)
{
double angle = 5 * i * 2 * Math.PI / 11;
SKPoint pt = new SKPoint(100 * (float)Math.Sin(angle),
-100 * (float)Math.Cos(angle));
if (i == 0)
{
HendecagramPath.MoveTo(pt);
}
else
{
HendecagramPath.LineTo(pt);
}
}
HendecagramPath.Close();
}
}
Если центр звезды — точка (0, 0), все точки звезды находятся в круге вокруг этой точки. Каждая точка — это сочетание значений синуса и косинуса угла, увеличивающегося на 5/11 градусов в 360 градусов. (Кроме того, можно создать 11-конечную звезду, увеличив угол на 2/11, 3/11 или 4/11 из круга.) Радиус этого круга задается как 100.
Если этот путь отрисовывается без каких-либо преобразований, центр будет расположен в левом верхнем углу SKCanvas
окна, и будет отображаться только четверть из него. HendecagramPage
Обработчик PaintSurface
вместо этого используется Translate
для плитки холста с несколькими копиями звезды, каждый из которых случайным образом цветом:
public class HendecagramArrayPage : ContentPage
{
Random random = new Random();
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
for (int x = 100; x < info.Width + 100; x += 200)
for (int y = 100; y < info.Height + 100; y += 200)
{
// Set random color
byte[] bytes = new byte[3];
random.NextBytes(bytes);
paint.Color = new SKColor(bytes[0], bytes[1], bytes[2]);
// Display the hendecagram
canvas.Save();
canvas.Translate(x, y);
canvas.DrawPath(HendecagramPath, paint);
canvas.Restore();
}
}
}
}
Ниже приведен результат:
Анимации часто включают преобразования. Страница анимации Hendecagram перемещает 11-конечную звезду вокруг круга. Класс HendecagramAnimationPage
начинается с некоторых полей и переопределяет OnAppearing
OnDisappearing
методы для запуска и остановки таймера Xamarin.Forms :
public class HendecagramAnimationPage : ContentPage
{
const double cycleTime = 5000; // in milliseconds
SKCanvasView canvasView;
Stopwatch stopwatch = new Stopwatch();
bool pageIsActive;
float angle;
public HendecagramAnimationPage()
{
Title = "Hedecagram Animation";
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;
angle = (float)(360 * t);
canvasView.InvalidateSurface();
if (!pageIsActive)
{
stopwatch.Stop();
}
return pageIsActive;
});
}
protected override void OnDisappearing()
{
base.OnDisappearing();
pageIsActive = false;
}
...
}
Поле angle
анимируется от 0 градусов до 360 градусов каждые 5 секунд. Обработчик PaintSurface
использует angle
свойство двумя способами: для указания цвета цвета в SKColor.FromHsl
методе и в качестве аргумента Math.Sin
для Math.Cos
управления расположением звезды:
public class HendecagramAnimationPage : ContentPage
{
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.Translate(info.Width / 2, info.Height / 2);
float radius = (float)Math.Min(info.Width, info.Height) / 2 - 100;
using (SKPaint paint = new SKPaint())
{
paint.Style = SKPaintStyle.Fill;
paint.Color = SKColor.FromHsl(angle, 100, 50);
float x = radius * (float)Math.Sin(Math.PI * angle / 180);
float y = -radius * (float)Math.Cos(Math.PI * angle / 180);
canvas.Translate(x, y);
canvas.DrawPath(HendecagramPage.HendecagramPath, paint);
}
}
}
Обработчик PaintSurface
дважды вызывает Translate
метод, сначала чтобы перевести в центр холста, а затем перевести в окружность окружности, центрированного вокруг (0, 0). Радиус круга должен быть максимально большим при сохранении звезды в пределах страницы:
Обратите внимание, что звезда сохраняет ту же ориентацию, что и она вращается вокруг центра страницы. Он вообще не поворачивается. Это задание для преобразования поворота.