Sdílet prostřednictvím


Pixely a jednotky nezávislé na zařízení

Prozkoumání rozdílů mezi souřadnicemi a Xamarin.Forms souřadnicemi SkiaSharp

Tento článek popisuje rozdíly v souřadnicovém systému používaném ve SkiaSharpu a Xamarin.Forms. Můžete získat informace pro převod mezi těmito dvěma souřadnicovými systémy a také kreslit grafiku, která vyplní určitou oblast:

Ovál, který vyplní obrazovku

Pokud už nějakou dobu programujete Xamarin.Forms , můžete mít pocit, Xamarin.Forms že máte souřadnice a velikosti. Kruhy nakreslené v obou předchozích článcích se vám můžou zdát trochu malé.

Tyto kruhy jsou ve srovnání s velikostmi Xamarin.Forms malé. SkiaSharp ve výchozím nastavení kreslí v jednotkách pixelů, zatímco Xamarin.Forms základy souřadnic a velikosti jsou na jednotce nezávislé na zařízení vytvořené podkladovou platformou. (Další informace o souřadnicovém Xamarin.Forms systému naleznete v kapitole 5. Práce s velikostmi knihy Vytváření mobilních aplikací s Xamarin.Forms.)

Stránka v ukázkovém programu s názvem Surface Size používá textový výstup SkiaSharp k zobrazení velikosti plochy displeje ze tří různých zdrojů:

  • Normální Xamarin.FormsWidth vlastnosti a Height vlastnosti objektu SKCanvasView .
  • Vlastnost CanvasSize objektu SKCanvasView .
  • Vlastnost Size SKImageInfo hodnoty, která je konzistentní s vlastnostmi Width použitými Height na dvou předchozích stránkách.

Třída SurfaceSizePage ukazuje, jak tyto hodnoty zobrazit. Konstruktor uloží SKCanvasView objekt jako pole, aby k němu bylo možné přistupovat v obslužné rutině PaintSurface události:

SKCanvasView canvasView;

public SurfaceSizePage()
{
    Title = "Surface Size";

    canvasView = new SKCanvasView();
    canvasView.PaintSurface += OnCanvasViewPaintSurface;
    Content = canvasView;
}

SKCanvas zahrnuje šest různých DrawText metod, ale tato DrawText metoda je nejjednodušší:

public void DrawText (String text, Single x, Single y, SKPaint paint)

Zadáte textový řetězec, souřadnice X a Y, kde má text začínat, a SKPaint objekt. Souřadnice X určuje umístění levé strany textu, ale pozor: Souřadnice Y určuje pozici účaří textu. Pokud jste někdy napsali ručně na linkovaný papír, je směrný plán čárou, na které znaky sedí a pod kterými sestupně (například ty na písmenech g, p, q a y) sestupně.

Objekt SKPaint umožňuje zadat barvu textu, rodinu písem a velikost textu. Ve výchozím nastavení má vlastnost hodnotu 12, což má za následek malý text na zařízeních s vysokým rozlišením, TextSize jako jsou telefony. V čemkoli, ale v nejjednodušších aplikacích budete potřebovat také informace o velikosti zobrazeného textu. Třída SKPaint definuje FontMetrics vlastnost a několik MeasureText metod, ale pro méně fancy potřeby poskytuje FontSpacing vlastnost doporučenou hodnotu pro řádkování po sobě jdoucích řádků textu.

Následující PaintSurface obslužná rutina vytvoří SKPaint objekt pro TextSize 40 pixelů, což je požadovaná svislá výška textu z horní části vzestupných hodnot do dolní části sestupných objektů. Hodnota FontSpacing , kterou SKPaint objekt vrátí, je o něco větší, asi 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);
}

Metoda začíná první řádek textu souřadnicí X 20 (pro malý okraj vlevo) a souřadnicí fontSpacingY , což je o něco víc, než je nutné k zobrazení úplné výšky prvního řádku textu v horní části plochy zobrazení. Po každém volání DrawTextse souřadnice Y zvýší o jeden nebo dva přírůstky fontSpacing.

Tady je spuštěný program:

Snímky obrazovky ukazují aplikaci Surface Size spuštěnou na dvou mobilních zařízeních.

Jak můžete vidět, CanvasSize vlastnost SKCanvasView a Size vlastnost SKImageInfo hodnoty jsou konzistentní při vykazování rozměrů pixelů. Vlastnosti Height a Width vlastnosti SKCanvasView jsou Xamarin.Forms vlastnosti a hlásí velikost zobrazení v jednotkách nezávislých na zařízení definovaných platformou.

Simulátor iOS sedm na levé straně má dva pixely na jednotku nezávislou na zařízení a Android Nexus 5 ve středu má tři pixely na jednotku. Proto má jednoduchý kruh zobrazený dříve různé velikosti na různých platformách.

Pokud chcete pracovat zcela v jednotkách nezávislých na zařízeních, můžete to udělat nastavením IgnorePixelScaling vlastnosti SKCanvasView na truehodnotu . Výsledky se ale nemusí líbit. SkiaSharp vykreslí grafiku na menší ploše zařízení s velikostí pixelů rovnající se velikosti zobrazení v jednotkách nezávislých na zařízeních. (Například SkiaSharp by použil plochu displeje 360 x 512 pixelů na Nexusu 5.) Potom vertikálně navýší velikost obrázku, což vede k znatelnému rastru jaggies.

Pokud chcete zachovat stejné rozlišení obrázků, lepším řešením je napsat vlastní jednoduché funkce pro převod mezi těmito dvěma souřadnicovými systémy.

Kromě DrawCircle metody definuje také dvě DrawOval metody, SKCanvas které nakreslely tři tečky. Tři tečky jsou definovány dvěma paprsky, nikoli jedním poloměrem. Označují se jako hlavní poloměr a vedlejší poloměr. Metoda DrawOval nakreslí tři tečky se dvěma paprsky paralelně s osami X a Y. (Pokud potřebujete nakreslit tři tečky se osami, které nejsou paralelní se osami X a Y, můžete použít transformaci otočení, jak je popsáno v článku.Otočit transformaci nebo grafickou cestu, jak je popsáno v článku Tři způsoby kreslení oblouku). Toto přetížení DrawOval metody pojmenuje dva parametry rx radii a ry indikuje, že jsou paralelní se osami X a Y:

public void DrawOval (Single cx, Single cy, Single rx, Single ry, SKPaint paint)

Je možné nakreslit tři tečky, které vyplní plochu displeje? Stránka Výplň tří teček ukazuje, jak na to. Obslužná rutina PaintSurface události ve třídě EllipseFillPage.xaml.cs odečte polovinu šířky tahu od xRadius a yRadius hodnot tak, aby odpovídala celému třemi tečkám a jeho obrysu na ploše zobrazení:

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

Tady je spuštěný:

Snímky obrazovky ukazují aplikaci Ellipse Fill spuštěnou na dvou mobilních zařízeních.

Druhá DrawOval metoda má SKRect argument, což je obdélník definovaný z hlediska souřadnic X a Y jeho levého horního a pravého dolního rohu. Ovál vyplní tento obdélník, což naznačuje, že by ho mohlo být možné použít na stránce Výplň se třemi tečkami takto:

SKRect rect = new SKRect(0, 0, info.Width, info.Height);
canvas.DrawOval(rect, paint);

To však zkracuje všechny okraje obrysu tří teček na čtyřech stranách. Musíte upravit všechny argumenty konstruktoru SKRect strokeWidth na základě toho, aby to fungovalo správně:

SKRect rect = new SKRect(strokeWidth / 2,
                         strokeWidth / 2,
                         info.Width - strokeWidth / 2,
                         info.Height - strokeWidth / 2);
canvas.DrawOval(rect, paint);