Die Verschiebungstransformation
Erfahren Sie, wie Sie die Übersetzungstransformation zum Verschieben von SkiaSharp-Grafiken verwenden.
Die einfachste Art der Transformation in SkiaSharp ist die Übersetzungs - oder Übersetzungstransformation . Diese Transformation verschiebt grafische Objekte in horizontaler und vertikaler Richtung. In einem Sinne ist die Übersetzung die unnötigste Transformation, da Sie in der Regel denselben Effekt erzielen können, indem Sie einfach die Koordinaten ändern, die Sie in der Zeichnungsfunktion verwenden. Beim Rendern eines Pfads werden jedoch alle Koordinaten im Pfad gekapselt, sodass es viel einfacher ist, eine Übersetzungstransformation anzuwenden, um den gesamten Pfad zu verschieben.
Übersetzung ist auch für Animationen und für einfache Texteffekte nützlich:
Die Translate
Methode in SKCanvas
weist zwei Parameter auf, die dazu führen, dass anschließend gezeichnete Grafikobjekte horizontal und vertikal verschoben werden:
public void Translate (Single dx, Single dy)
Diese Argumente können negativ sein. Eine zweite Translate
Methode kombiniert die beiden Übersetzungswerte in einem einzelnen SKPoint
Wert:
public void Translate (SKPoint point)
Auf der Seite "Kumulierte Übersetzung " des Beispielprogramms wird veranschaulicht, dass mehrere Aufrufe der Translate
Methode kumulativ sind. Die AccumulatedTranslatePage
Klasse zeigt 20 Versionen desselben Rechtecks an, wobei jeder Abstand vom vorherigen Rechteck nur ausreichend ist, sodass sie sich entlang der Diagonale erstrecken. Dies ist der PaintSurface
Ereignishandler:
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);
}
}
}
Die aufeinander folgenden Rechtecke verleiten auf der Seite:
Wenn die angesammelten Übersetzungsfaktoren dx
und dy
der punkt, den Sie in einer Zeichnungsfunktion angeben, ist (x
, y
), wird das grafische Objekt an dem Punkt (x'
, y'
), wobei:
x' = x + dx
y' = y + dy
Diese werden als Transformationsformeln für die Übersetzung bezeichnet. Die Standardwerte und dx
dy
für ein neues SKCanvas
sind 0.
Es ist üblich, die Übersetzungstransformation für Schatteneffekte und ähnliche Techniken zu verwenden, wie die Seite "Texteffekte übersetzen" veranschaulicht. Dies ist der relevante Teil des PaintSurface
Handlers in der TranslateTextEffectsPage
Klasse:
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);
}
In jedem der drei Beispiele wird die Anzeige des Texts aufgerufen, Translate
um ihn von der von den und y
den x
Variablen angegebenen Position zu versatzen. Anschließend wird der Text wieder in einer anderen Farbe ohne Übersetzungseffekt angezeigt:
Jedes der drei Beispiele zeigt eine andere Methode zum Negieren des Translate
Anrufs:
Im ersten Beispiel wird einfach wieder aufgerufen Translate
, aber mit negativen Werten. Da die Translate
Aufrufe kumulativ sind, stellt diese Aufrufsequenz einfach die Gesamtübersetzung in die Standardwerte null wieder her.
Das zweite Beispiel ruft .ResetMatrix
Dies bewirkt, dass alle Transformationen zum Standardzustand zurückkehren.
Im dritten Beispiel wird der Zustand des SKCanvas
Objekts mit einem Aufruf Save
gespeichert und anschließend mit einem Aufruf wiederhergestellt Restore
. Dies ist die vielseitigste Methode zum Bearbeiten von Transformationen für eine Reihe von Zeichnungsvorgängen. Diese Save
und Restore
Aufrufe funktionieren wie ein Stapel: Sie können mehrmals aufrufen Save
und dann in umgekehrter Reihenfolge aufrufen Restore
, um zu vorherigen Zuständen zurückzukehren. Die Save
Methode gibt eine ganze Zahl zurück, und Sie können diese ganze Zahl RestoreToCount
mehrmals übergeben, um sie effektiv aufzurufen Restore
. Die SaveCount
Eigenschaft gibt die Anzahl der Zustände zurück, die derzeit im Stapel gespeichert sind.
Sie können die SKAutoCanvasRestore
Klasse auch zum Wiederherstellen des Canvaszustands verwenden. Der Konstruktor dieser Klasse soll in einer using
Anweisung aufgerufen werden. Der Canvaszustand wird automatisch am Ende des using
Blocks wiederhergestellt.
Sie müssen sich jedoch keine Gedanken über Transformationen machen, die von einem Aufruf des PaintSurface
Handlers zur nächsten übertragen werden. Jeder neue Aufruf, um ein neues SKCanvas
Objekt mit Standardtransformationen zu PaintSurface
liefern.
Eine weitere häufige Verwendung der Translate
Transformation ist das Rendern eines visuellen Objekts, das ursprünglich mithilfe von Koordinaten erstellt wurde, die für die Zeichnung geeignet sind. Sie können beispielsweise Koordinaten für eine analoge Uhr mit einer Mitte am Punkt (0, 0) angeben. Sie können dann Transformationen verwenden, um die Uhr an der gewünschten Stelle anzuzeigen. Diese Technik wird auf der Seite [Hendecagram Array] veranschaulicht. Die HendecagramArrayPage
Klasse beginnt mit dem Erstellen eines SKPath
Objekts für einen 11-spitzen Stern. Das HendecagramPath
Objekt wird als öffentlich, statisch und schreibgeschützt definiert, sodass es von anderen Demonstrationsprogrammen aus aufgerufen werden kann. Sie wird in einem statischen Konstruktor erstellt:
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();
}
}
Wenn die Mitte des Sterns der Punkt (0, 0) ist, befinden sich alle Punkte des Sterns auf einem Kreis, der diesen Punkt umgibt. Jeder Punkt ist eine Kombination aus Sinus- und Kosinuswerten eines Winkels, der um 5/11tel von 360 Grad zunimmt. (Es ist auch möglich, einen 11-spitzen Stern zu erstellen, indem der Winkel um 2/11, 3/11th oder 4/11th des Kreises erhöht wird.) Der Radius dieses Kreises wird als 100 festgelegt.
Wenn dieser Pfad ohne Transformationen gerendert wird, wird die Mitte in der oberen linken Ecke des SKCanvas
Bereichs positioniert, und nur ein Viertel davon ist sichtbar. Der PaintSurface
Handler HendecagramPage
verwendet Translate
stattdessen, um den Zeichenbereich mit mehreren Kopien des Sterns zu kacheln, die jeweils zufällig gefärbt sind:
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();
}
}
}
}
Das Ergebnis lautet wie folgt:
Animationen umfassen häufig Transformationen. Die Hendekagramanimationsseite verschiebt den 11-spitzen Stern in einem Kreis um. Die HendecagramAnimationPage
Klasse beginnt mit einigen Feldern und Außerkraftsetzungen der OnAppearing
methoden OnDisappearing
, um einen Xamarin.Forms Timer zu starten und zu beenden:
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;
}
...
}
Das angle
Feld wird alle 5 Sekunden von 0 Grad bis 360 Grad animiert. Der PaintSurface
Handler verwendet die angle
Eigenschaft auf zwei Arten: zum Angeben des Farbtons in der SKColor.FromHsl
Methode und als Argument für die Math.Sin
Und Math.Cos
Methoden zum Steuern der Position des Sterns:
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);
}
}
}
Der PaintSurface
Handler ruft die Translate
Methode zweimal auf, zuerst in die Mitte des Zeichenbereichs zu übersetzen und dann in den Umfang eines kreiszentrierten Kreises (0, 0) zu übersetzen. Der Radius des Kreises ist so groß wie möglich, während der Stern weiterhin innerhalb der Grenzen der Seite bleibt:
Beachten Sie, dass der Stern Standard die gleiche Ausrichtung wie er sich um die Mitte der Seite dreht. Es dreht sich überhaupt nicht. Das ist ein Auftrag für eine Drehtransformation.