Pixel e unità di misura indipendenti dal dispositivo
Esplorare le differenze tra coordinate e Xamarin.Forms coordinate SkiaSharp
Questo articolo illustra le differenze nel sistema di coordinate usato in SkiaSharp e Xamarin.Forms. È possibile ottenere informazioni da convertire tra i due sistemi di coordinate e disegnare anche elementi grafici che riempiono una determinata area:
Se hai programmato Xamarin.Forms per un po' di tempo, potresti avere un'impressione per Xamarin.Forms coordinate e dimensioni. I cerchi disegnati nei due articoli precedenti potrebbero sembrare un po 'piccoli per voi.
Tali cerchi sono piccoli rispetto alle Xamarin.Forms dimensioni. Per impostazione predefinita, SkiaSharp disegna in unità di pixel, mentre Xamarin.Forms basa le coordinate e le dimensioni su un'unità indipendente dal dispositivo stabilita dalla piattaforma sottostante. Altre informazioni sul Xamarin.Forms sistema di coordinate sono disponibili nel capitolo 5. Gestione delle dimensioni del libro Creazione di app per dispositivi mobili con Xamarin.Forms.)
La pagina del programma di esempio intitolata Surface Size usa l'output di testo SkiaSharp per visualizzare le dimensioni della superficie di visualizzazione da tre origini diverse:
- Proprietà normali Xamarin.Forms
Width
eHeight
dell'oggettoSKCanvasView
. - Proprietà
CanvasSize
dell'oggettoSKCanvasView
. - Proprietà
Size
delSKImageInfo
valore, coerente con leWidth
proprietà eHeight
utilizzate nelle due pagine precedenti.
La SurfaceSizePage
classe mostra come visualizzare questi valori. Il costruttore salva l'oggetto SKCanvasView
come campo, in modo che sia accessibile nel PaintSurface
gestore eventi:
SKCanvasView canvasView;
public SurfaceSizePage()
{
Title = "Surface Size";
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
SKCanvas
include sei metodi diversi DrawText
, ma questo DrawText
metodo è il più semplice:
public void DrawText (String text, Single x, Single y, SKPaint paint)
Specificare la stringa di testo, le coordinate X e Y in cui iniziare il testo e un SKPaint
oggetto . La coordinata X specifica dove è posizionato il lato sinistro del testo, ma osserva: la coordinata Y specifica la posizione della linea di base del testo. Se hai mai scritto a mano su carta rivestita, la linea di base è la linea su cui siedono i caratteri e sotto i discendenti (ad esempio quelli sulle lettere g, p, q e y) discendono.
L'oggetto SKPaint
consente di specificare il colore del testo, la famiglia di caratteri e la dimensione del testo. Per impostazione predefinita, la TextSize
proprietà ha un valore pari a 12, che comporta un testo minuscolo su dispositivi ad alta risoluzione, ad esempio telefoni. In qualsiasi modo, ma le applicazioni più semplici, sono necessarie anche alcune informazioni sulle dimensioni del testo visualizzato. La SKPaint
classe definisce una FontMetrics
proprietà e diversi MeasureText
metodi, ma per esigenze meno fantasia, la FontSpacing
proprietà fornisce un valore consigliato per la spaziatura di righe di testo successive.
Il gestore seguente PaintSurface
crea un SKPaint
oggetto per un TextSize
oggetto di 40 pixel, ovvero l'altezza verticale desiderata del testo dalla parte superiore degli ascendenti alla parte inferiore dei discendenti. Il FontSpacing
valore restituito dall'oggetto SKPaint
è leggermente maggiore di quello, circa 47 pixel.
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);
}
Il metodo inizia la prima riga di testo con una coordinata X pari a 20 (per un piccolo margine a sinistra) e una coordinata Y di fontSpacing
, che è leggermente superiore a quella necessaria per visualizzare l'altezza completa della prima riga di testo nella parte superiore della superficie di visualizzazione. Dopo ogni chiamata a DrawText
, la coordinata Y viene aumentata di uno o due incrementi di fontSpacing
.
Ecco il programma in esecuzione:
Come si può notare, la CanvasSize
proprietà di SKCanvasView
e la Size
proprietà del SKImageInfo
valore sono coerenti nel segnalare le dimensioni pixel. Le Height
proprietà e Width
di SKCanvasView
sono Xamarin.Forms proprietà e segnalano le dimensioni della visualizzazione nelle unità indipendenti dal dispositivo definite dalla piattaforma.
Il simulatore iOS sette a sinistra ha due pixel per unità indipendente dal dispositivo e Android Nexus 5 nel centro ha tre pixel per unità. Ecco perché il cerchio semplice mostrato in precedenza ha dimensioni diverse su piattaforme diverse.
Se si preferisce lavorare interamente in unità indipendenti dal dispositivo, è possibile farlo impostando la IgnorePixelScaling
proprietà di SKCanvasView
su true
. Tuttavia, è possibile che non si vogliano i risultati. SkiaSharp esegue il rendering della grafica su una superficie del dispositivo più piccola, con dimensioni in pixel uguali alle dimensioni della visualizzazione in unità indipendenti dal dispositivo. Ad esempio, SkiaSharp userebbe una superficie di visualizzazione di 360 x 512 pixel sul Nexus 5. Aumenta quindi le dimensioni dell'immagine, con conseguenti jaggie bitmap evidenti.
Per mantenere la stessa risoluzione delle immagini, una soluzione migliore consiste nel scrivere funzioni semplici da convertire tra i due sistemi di coordinate.
Oltre al DrawCircle
metodo , SKCanvas
definisce anche due DrawOval
metodi che disegnano un'ellisse. Un'ellisse è definita da due raggi anziché da un singolo raggio. Questi sono noti come raggio principale e raggio secondario. Il DrawOval
metodo disegna un'ellisse con i due raggi paralleli agli assi X e Y. Se è necessario disegnare un'ellisse con assi non paralleli agli assi X e Y, è possibile usare una trasformazione di rotazione come illustrato nell'articolo Ruota trasformazione o percorso grafico come illustrato nell'articolo Tre modi per disegnare un arco. Questo overload del DrawOval
metodo denomina i due parametri rx
di radii e ry
per indicare che sono paralleli agli assi X e Y:
public void DrawOval (Single cx, Single cy, Single rx, Single ry, SKPaint paint)
È possibile disegnare un'ellisse che riempie la superficie di visualizzazione? La pagina Riempimento ellisse illustra come. Il PaintSurface
gestore eventi nella classe EllipseFillPage.xaml.cs sottrae metà della larghezza del tratto dai xRadius
valori e yRadius
per adattare l'intera ellisse e il relativo contorno all'interno della superficie di visualizzazione:
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);
}
Di seguito è in esecuzione:
L'altro DrawOval
metodo ha un SKRect
argomento, ovvero un rettangolo definito in termini di coordinate X e Y dell'angolo superiore sinistro e inferiore destro. L'ovale riempie il rettangolo, che suggerisce che potrebbe essere possibile usarlo nella pagina Riempimento ellisse come segue:
SKRect rect = new SKRect(0, 0, info.Width, info.Height);
canvas.DrawOval(rect, paint);
Tuttavia, che tronca tutti i bordi del contorno dell'ellisse sui quattro lati. È necessario modificare tutti gli argomenti del SKRect
costruttore in strokeWidth
base a per fare in modo che funzioni correttamente:
SKRect rect = new SKRect(strokeWidth / 2,
strokeWidth / 2,
info.Width - strokeWidth / 2,
info.Height - strokeWidth / 2);
canvas.DrawOval(rect, paint);