Trasformazione di traslazione
Informazioni su come usare la trasformazione translate per spostare la grafica SkiaSharp
Il tipo più semplice di trasformazione in SkiaSharp è la trasformazione traslazione o traslazione . Questa trasformazione sposta gli oggetti grafici nelle direzioni orizzontali e verticali. In un certo senso, la conversione è la trasformazione più superflua perché in genere è possibile ottenere lo stesso effetto semplicemente modificando le coordinate che si utilizzano nella funzione di disegno. Quando si esegue il rendering di un percorso, tuttavia, tutte le coordinate vengono incapsulate nel percorso, quindi è molto più semplice applicare una trasformazione di conversione per spostare l'intero percorso.
La traduzione è utile anche per l'animazione e per gli effetti di testo semplici:
Il Translate
metodo in SKCanvas
ha due parametri che determinano lo spostamento orizzontale e verticale degli oggetti grafici disegnati successivamente:
public void Translate (Single dx, Single dy)
Questi argomenti possono essere negativi. Un secondo Translate
metodo combina i due valori di conversione in un singolo SKPoint
valore:
public void Translate (SKPoint point)
La pagina Translate accumulata del programma di esempio dimostra che più chiamate del Translate
metodo sono cumulative. La AccumulatedTranslatePage
classe visualizza 20 versioni dello stesso rettangolo, ognuna delle quali rispetto al rettangolo precedente è sufficiente per estendersi lungo la diagonale. Ecco il PaintSurface
gestore eventi:
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);
}
}
}
I rettangoli successivi si spostano verso il basso nella pagina:
Se i fattori di traslazione accumulati sono dx
e dy
e il punto specificato in una funzione di disegno è (x
, y
), il rendering dell'oggetto grafico viene eseguito nel punto (x'
, y'
), dove:
x' = x + dx
y' = y + dy
Queste formule sono note come formule di trasformazione per la traduzione. I valori predefiniti di dx
e dy
per un nuovo SKCanvas
sono 0.
È comune usare la trasformazione traduci per gli effetti di ombreggiatura e tecniche simili, come illustrato nella pagina Translate Text Effects .It is common to use the translate transform for shadow effects and similar techniques, as the Translate Text Effects page illustrate. Ecco la parte pertinente del PaintSurface
gestore nella TranslateTextEffectsPage
classe :
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 ognuno dei tre esempi viene Translate
chiamato per visualizzare il testo per compensarlo dalla posizione specificata dalle x
variabili e y
. Il testo viene quindi visualizzato di nuovo in un altro colore senza alcun effetto di traduzione:
Ognuno dei tre esempi mostra un modo diverso per negare la Translate
chiamata:
Il primo esempio chiama Translate
semplicemente di nuovo ma con valori negativi. Poiché le Translate
chiamate sono cumulative, questa sequenza di chiamate ripristina semplicemente la conversione totale ai valori predefiniti pari a zero.
Il secondo esempio chiama ResetMatrix
. In questo modo tutte le trasformazioni tornano allo stato predefinito.
Il terzo esempio salva lo stato dell'oggetto SKCanvas
con una chiamata a Save
e quindi ripristina lo stato con una chiamata a Restore
. Questo è il modo più versatile per manipolare le trasformazioni per una serie di operazioni di disegno. Queste Save
e Restore
chiamano una funzione come uno stack: è possibile chiamare Save
più volte e quindi chiamare Restore
in sequenza inversa per tornare agli stati precedenti. Il Save
metodo restituisce un numero intero ed è possibile passare tale intero a per RestoreToCount
chiamare Restore
in modo efficace più volte. La SaveCount
proprietà restituisce il numero di stati attualmente salvati nello stack.
È anche possibile usare la SKAutoCanvasRestore
classe per ripristinare lo stato dell'area di disegno. Il costruttore di questa classe deve essere chiamato in un'istruzione using
. Lo stato dell'area di disegno viene ripristinato automaticamente alla fine del using
blocco.
Tuttavia, non è necessario preoccuparsi delle trasformazioni che passano da una chiamata del PaintSurface
gestore alla successiva. Ogni nuova chiamata a recapita PaintSurface
un nuovo SKCanvas
oggetto con trasformazioni predefinite.
Un altro uso comune della trasformazione consiste nel rendering di un oggetto visivo originariamente creato utilizzando coordinate utili per il Translate
disegno. Ad esempio, è possibile specificare le coordinate per un orologio analogico con un centro nel punto (0, 0). È quindi possibile usare le trasformazioni per visualizzare l'orologio in cui si desidera. Questa tecnica è illustrata nella pagina [Hendecagram Array]. La HendecagramArrayPage
classe inizia creando un SKPath
oggetto per una stella a 11 punte. L'oggetto HendecagramPath
è definito come pubblico, statico e di sola lettura in modo che sia accessibile da altri programmi dimostrativi. Viene creato in un costruttore statico:
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();
}
}
Se il centro della stella è il punto (0, 0), tutti i punti della stella si trovano su un cerchio che circonda quel punto. Ogni punto è una combinazione di valori seno e coseno di un angolo che aumenta di 5/11° di 360 gradi. È anche possibile creare una stella a 11 punte aumentando l'angolo di 2/11, 3/11 o 4/11 del cerchio. Il raggio del cerchio è impostato su 100.
Se il rendering di questo percorso viene eseguito senza alcuna trasformazione, il centro verrà posizionato nell'angolo superiore sinistro dell'oggetto SKCanvas
e sarà visibile solo un quarto di esso. Il PaintSurface
gestore di HendecagramPage
usa Translate
invece per affiancare l'area di disegno con più copie della stella, ognuna colorata in modo casuale:
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();
}
}
}
}
Il risultato è il seguente:
Le animazioni spesso comportano trasformazioni. La pagina Animazione hendecagram sposta la stella a 11 punte intorno in un cerchio. La HendecagramAnimationPage
classe inizia con alcuni campi ed esegue l'override OnAppearing
dei metodi e OnDisappearing
per avviare e arrestare un Xamarin.Forms timer:
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;
}
...
}
Il angle
campo viene animato da 0 a 360 gradi ogni 5 secondi. Il PaintSurface
gestore usa la angle
proprietà in due modi: per specificare la tonalità del colore nel SKColor.FromHsl
metodo e come argomento per i Math.Sin
metodi e Math.Cos
per gestire la posizione della stella:
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);
}
}
}
Il PaintSurface
gestore chiama il Translate
metodo due volte, prima per convertirlo al centro dell'area di disegno e quindi per traslare nella circonferenza di un cerchio centrato intorno (0, 0). Il raggio del cerchio è impostato per essere il più grande possibile, mantenendo comunque la stella entro i confini della pagina:
Si noti che la stella mantiene lo stesso orientamento che ruota intorno al centro della pagina. Non ruota affatto. Si tratta di un processo per una trasformazione di rotazione.