Pixel e unità di misura indipendenti dal dispositivo

Download Sample Scaricare l'esempio

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:

An oval that fills the screen

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 SkewSharpFormsDemos intitolata Surface Size usa l'output di testo SkiaSharp per mostrare le dimensioni della superficie di visualizzazione da tre origini diverse:

  • Proprietà normali Xamarin.FormsWidth e Height dell'oggetto SKCanvasView .
  • Proprietà CanvasSize dell'oggetto SKCanvasView.
  • Proprietà Size del SKImageInfo valore, coerente con le Width proprietà e Height 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:

Screenshots show the Surface Size app running on two mobile devices.

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:

Screenshots show the Ellipse Fill app running on two mobile devices.

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);