Základní grafika v Xamarin.iOS

Tento článek popisuje architektury Core Graphics iOS. Ukazuje, jak pomocí základní grafiky kreslit geometrii, obrázky a soubory PDF.

iOS zahrnuje základní grafickou architekturu, která poskytuje podporu výkresu nízké úrovně. Tyto architektury umožňují bohaté grafické funkce v uiKitu.

Základní grafika je 2D grafická architektura nízké úrovně, která umožňuje nakreslit nezávislou grafiku na zařízení. Všechny 2D výkresy v UIKitu interně používají základní grafiku.

Základní grafika podporuje kreslení v řadě scénářů, mezi které patří:

Geometrický prostor

Bez ohledu na scénář se všechny kresby provedené se základní grafikou provádí v geometrickém prostoru, což znamená, že funguje v abstraktních bodech místo pixelů. Popisujete, co chcete nakreslit z hlediska geometrie a stavu kreslení, jako jsou barvy, styly čar atd. a základní grafika překládá všechno na pixely. Takový stav se přidá do grafického kontextu, který si můžete představit jako plátno malíře.

Tento přístup má několik výhod:

  • Kód výkresu se stane dynamickým a následně může upravovat grafiku za běhu.
  • Snížení potřeby statických obrázků v sadě aplikací může snížit velikost aplikace.
  • Grafika se stává odolnější vůči změnám rozlišení napříč zařízeními.

Kreslení v podtřídě UIView

Každý UIView má metodu Draw , která je volána systémem, když je potřeba nakreslit. Přidání kódu výkresu do zobrazení, podtřídy UIView a přepsání Draw:

public class TriangleView : UIView
{
    public override void Draw (CGRect rect)
    {
        base.Draw (rect);
    }
}

Kreslení by nikdy nemělo být volána přímo. Volá se systémem během zpracování smyčky spuštění. Při prvním procházení smyčky spuštění po přidání zobrazení do hierarchie zobrazení se volá jeho Draw metoda. Následné volání, ke kterým dojde Draw , když je zobrazení označené jako potřeba kreslit voláním SetNeedsDisplaySetNeedsDisplayInRect nebo zobrazením.

Vzor grafického kódu

Kód v implementaci Draw by měl popsat, co chce nakreslit. Kód výkresu se řídí vzorem, ve kterém nastaví určitý stav výkresu a zavolá metodu, která ji požádá o vykreslení. Tento model lze generalizovat následujícím způsobem:

  1. Získejte kontext grafiky.

  2. Nastavte atributy výkresu.

  3. Vytvořte určitou geometrii z primitiv kreslení.

  4. Zavolejte metodu Kreslení nebo Tah.

Příklad základního výkresu

Představte si například následující fragment kódu:

//get graphics context
using (CGContext g = UIGraphics.GetCurrentContext ()) {

    //set up drawing attributes
    g.SetLineWidth (10);
    UIColor.Blue.SetFill ();
    UIColor.Red.SetStroke ();

    //create geometry
    var path = new CGPath ();

    path.AddLines (new CGPoint[]{
    new CGPoint (100, 200),
    new CGPoint (160, 100),
    new CGPoint (220, 200)});

    path.CloseSubpath ();

    //add geometry to graphics context and draw it
    g.AddPath (path);
    g.DrawPath (CGPathDrawingMode.FillStroke);
}

Pojďme tento kód rozdělit:

using (CGContext g = UIGraphics.GetCurrentContext ()) {
...
}

S tímto řádkem nejprve získá aktuální grafický kontext, který se má použít pro kreslení. Kontext grafiky si můžete představit jako plátno, na které se výkres děje, obsahující veškerý stav výkresu, jako jsou barvy tahu a výplně, stejně jako geometrie, na které se má kreslit.

g.SetLineWidth (10);
UIColor.Blue.SetFill ();
UIColor.Red.SetStroke ();

Po získání kontextu grafiky kód nastaví některé atributy, které se mají použít při kreslení, viz výše. V tomto případě se nastaví šířka čáry, tahy a barvy výplně. Všechny následné výkresy pak budou tyto atributy používat, protože jsou udržovány ve stavu grafického kontextu.

K vytvoření geometrie kód používá metodu CGPath, která umožňuje popis grafické cesty z čar a křivek. V tomto případě cesta přidá čáry spojující matici bodů, které tvoří trojúhelník. Jak je znázorněno pod základní grafikou, používá souřadnicový systém pro výkres zobrazení, kde je původ v levém horním rohu, s kladným x-přímým směrem doprava a směr kladné-y dolů:

var path = new CGPath ();

path.AddLines (new CGPoint[]{
new CGPoint (100, 200),
new CGPoint (160, 100),
new CGPoint (220, 200)});

path.CloseSubpath ();

Po vytvoření cesty se přidá do grafického kontextu, aby volání AddPath a DrawPath v uvedeném pořadí mohlo kreslit.

Výsledné zobrazení je znázorněno níže:

The sample output triangle

Vytváření přechodových výplní

K dispozici jsou také bohatší formy výkresu. Základní grafika například umožňuje vytvářet přechodové výplně a používat cesty výřezu. Pokud chcete nakreslit přechodovou výplň uvnitř cesty z předchozího příkladu, nejprve je potřeba nastavit cestu výřezu:

// add the path back to the graphics context so that it is the current path
g.AddPath (path);
// set the current path to be the clipping path
g.Clip ();

Nastavení aktuální cesty jako cesty výřezu omezuje všechny následné výkresy v rámci geometrie cesty, jako je například následující kód, který nakreslí lineární přechod:

// the color space determines how Core Graphics interprets color information
    using (CGColorSpace rgb = CGColorSpace.CreateDeviceRGB()) {
        CGGradient gradient = new CGGradient (rgb, new CGColor[] {
        UIColor.Blue.CGColor,
        UIColor.Yellow.CGColor
    });

// draw a linear gradient
    g.DrawLinearGradient (
        gradient,
        new CGPoint (path.BoundingBox.Left, path.BoundingBox.Top),
        new CGPoint (path.BoundingBox.Right, path.BoundingBox.Bottom),
        CGGradientDrawingOptions.DrawsBeforeStartLocation);
    }

Tyto změny vytvářejí přechodovou výplň, jak je znázorněno níže:

The example with a gradient fill

Úprava vzorů čar

Atributy výkresu čar lze také upravit pomocí základní grafiky. To zahrnuje změnu šířky čáry a barvy tahu a samotného vzoru čáry, jak je vidět v následujícím kódu:

//use a dashed line
g.SetLineDash (0, new nfloat[] { 10, 4 * (nfloat)Math.PI });

Přidání tohoto kódu před všemi operacemi kreslení vede k přerušovaným tahům o délce 10 jednotek s 4 jednotkami mezer mezi pomlčkami, jak je znázorněno níže:

Adding this code before any drawing operations results in dashed strokes

Všimněte si, že při použití sjednoceného rozhraní API v Xamarin.iOS musí být typ pole a nfloattaké musí být explicitně přetypován na Math.PI.

Kreslení obrázků a textu

Kromě cest kreslení v grafickém kontextu zobrazení podporuje základní grafika také obrázky a text výkresu. Pokud chcete nakreslit obrázek, jednoduše vytvořte CGImage a předejte ho volání DrawImage :

public override void Draw (CGRect rect)
{
    base.Draw (rect);

    using(CGContext g = UIGraphics.GetCurrentContext ()){
        g.DrawImage (rect, UIImage.FromFile ("MyImage.png").CGImage);
    }
}

Tím se ale vytvoří obrázek vzhůru nohama, jak je znázorněno níže:

An image drawn upside down

Důvodem je základní původ grafiky pro kreslení obrázků v levém dolním rohu, zatímco zobrazení má svůj původ v levém horním rohu. Therefore, to display the image correctly, the origin needs to be modified, which can be accomplished by modifying the Current Transformation Matrix(CTM). CTM definuje, kde body žijí, označované také jako uživatelské místo. Převrácení CTM ve směru y a jeho posunutí o výšku ohraničení v záporném směru y může překlopit obrázek.

Kontext grafiky má pomocné metody transformace CTM. V tomto případě ScaleCTM výkres překlopíte a TranslateCTM posunete ho doleva nahoře, jak je znázorněno níže:

public override void Draw (CGRect rect)
{
    base.Draw (rect);

    using (CGContext g = UIGraphics.GetCurrentContext ()) {

        // scale and translate the CTM so the image appears upright
        g.ScaleCTM (1, -1);
        g.TranslateCTM (0, -Bounds.Height);
        g.DrawImage (rect, UIImage.FromFile ("MyImage.png").CGImage);
}

Výsledný obrázek se pak zobrazí přímo:

The sample image displayed upright

Důležité

Změny kontextu grafiky platí pro všechny následné operace výkresu. Proto při transformaci CTM ovlivní jakýkoli další výkres. Pokud jste například nakreslili trojúhelník po transformaci CTM, zobrazí se vzhůru nohama.

Přidání textu do obrázku

Stejně jako u cest a obrázků zahrnuje kreslený text s jádrovou grafikou stejný základní vzor nastavení nějakého stavu grafiky a volání metody pro kreslení. V případě textu je ShowTextmetoda pro zobrazení textu . Při přidání do příkladu výkresu obrázku nakreslí následující kód nějaký text pomocí základní grafiky:

public override void Draw (RectangleF rect)
{
    base.Draw (rect);

    // image drawing code omitted for brevity ...

    // translate the CTM by the font size so it displays on screen
    float fontSize = 35f;
    g.TranslateCTM (0, fontSize);

    // set general-purpose graphics state
    g.SetLineWidth (1.0f);
    g.SetStrokeColor (UIColor.Yellow.CGColor);
    g.SetFillColor (UIColor.Red.CGColor);
    g.SetShadow (new CGSize (5, 5), 0, UIColor.Blue.CGColor);

    // set text specific graphics state
    g.SetTextDrawingMode (CGTextDrawingMode.FillStroke);
    g.SelectFont ("Helvetica", fontSize, CGTextEncoding.MacRoman);

    // show the text
    g.ShowText ("Hello Core Graphics");
}

Jak vidíte, nastavení stavu grafiky pro kreslení textu je podobné geometrii výkresu. Pro kreslení textu se ale použije i režim kreslení textu a písmo. V tomto případě se také použije stín, i když použití stínů funguje stejně pro kreslení cest.

Výsledný text se zobrazí s obrázkem, jak je znázorněno níže:

The resulting text is displayed with the image

obrázky Memory-Backed

Kromě kreslení do grafického kontextu zobrazení podporuje základní grafika obrázky nakreslené paměti, označované také jako kreslení mimo obrazovku. To vyžaduje:

  • Vytvoření grafického kontextu, který je podporován rastrovým obrázkem v paměti
  • Nastavení stavu výkresu a vydávání příkazů výkresu
  • Získání obrázku z kontextu
  • Odebrání kontextu

Draw Na rozdíl od metody, kde je kontext zadaný zobrazením, v tomto případě vytvoříte kontext jedním ze dvou způsobů:

  1. UIGraphics.BeginImageContext Voláním (nebo BeginImageContextWithOptions)

  2. Vytvořením nové CGBitmapContextInstance

CGBitmapContextInstance je užitečná při práci přímo s bity obrázků, například pro případy, kdy používáte vlastní algoritmus manipulace s obrázky. Ve všech ostatních případech byste měli použít BeginImageContext nebo BeginImageContextWithOptions.

Jakmile máte kontext obrázku, přidání kódu výkresu UIView je stejně jako v podtřídě. Například příklad kódu použitý dříve k kreslení trojúhelníku lze použít k kreslení na obrázek v paměti místo v paměti UIView, jak je znázorněno níže:

UIImage DrawTriangle ()
{
    UIImage triangleImage;

    //push a memory backed bitmap context on the context stack
    UIGraphics.BeginImageContext (new CGSize (200.0f, 200.0f));

    //get graphics context
    using(CGContext g = UIGraphics.GetCurrentContext ()){

        //set up drawing attributes
        g.SetLineWidth(4);
        UIColor.Purple.SetFill ();
        UIColor.Black.SetStroke ();

        //create geometry
        path = new CGPath ();

        path.AddLines(new CGPoint[]{
            new CGPoint(100,200),
            new CGPoint(160,100),
            new CGPoint(220,200)});

        path.CloseSubpath();

        //add geometry to graphics context and draw it
        g.AddPath(path);
        g.DrawPath(CGPathDrawingMode.FillStroke);

        //get a UIImage from the context
        triangleImage = UIGraphics.GetImageFromCurrentImageContext ();
    }

    return triangleImage;
}

Běžným použitím výkresu na rastrový obrázek založený na paměti je zachytit obrázek z libovolného UIViewobrázku . Například následující kód vykreslí vrstvu zobrazení do rastrového kontextu a vytvoří z UIImage něj:

UIGraphics.BeginImageContext (cellView.Frame.Size);

//render the view's layer in the current context
anyView.Layer.RenderInContext (UIGraphics.GetCurrentContext ());

//get a UIImage from the context
UIImage anyViewImage = UIGraphics.GetImageFromCurrentImageContext ();
UIGraphics.EndImageContext ();

Nakreslené soubory PDF

Kromě obrázků podporuje základní grafika výkres PDF. Stejně jako obrázky můžete vykreslit PDF v paměti a také číst PDF pro vykreslování v souboru UIView.

PDF v uiView

Core Graphics také podporuje čtení PDF ze souboru a jeho vykreslení v zobrazení pomocí CGPDFDocument třídy. Třída CGPDFDocument představuje soubor PDF v kódu a lze ho použít ke čtení a kreslení stránek.

Například následující kód v UIView podtřídě čte PDF ze souboru do CGPDFDocument:

public class PDFView : UIView
{
    CGPDFDocument pdfDoc;

    public PDFView ()
    {
        //create a CGPDFDocument from file.pdf included in the main bundle
        pdfDoc = CGPDFDocument.FromFile ("file.pdf");
    }

     public override void Draw (Rectangle rect)
    {
        ...
    }
}

Metoda Draw pak může použít CGPDFDocument ke čtení stránky CGPDFPage a vykreslit ji voláním DrawPDFPage, jak je znázorněno níže:

public override void Draw (CGRect rect)
{
    base.Draw (rect);

    //flip the CTM so the PDF will be drawn upright
    using (CGContext g = UIGraphics.GetCurrentContext ()) {
        g.TranslateCTM (0, Bounds.Height);
        g.ScaleCTM (1, -1);

        // render the first page of the PDF
        using (CGPDFPage pdfPage = pdfDoc.GetPage (1)) {

        //get the affine transform that defines where the PDF is drawn
        CGAffineTransform t = pdfPage.GetDrawingTransform (CGPDFBox.Crop, rect, 0, true);

        //concatenate the pdf transform with the CTM for display in the view
        g.ConcatCTM (t);

        //draw the pdf page
        g.DrawPDFPage (pdfPage);
        }
    }
}

Memory-Backed PDF

Pro pdf v paměti musíte vytvořit kontext PDF voláním BeginPDFContext. Výkres do PDF je členitý na stránky. Každá stránka je spuštěna voláním BeginPDFPage a dokončením voláním EndPDFContent, s grafickým kódem mezi. Stejně jako u výkresu obrázků používá výkres PDF založený na paměti původ v levém dolním rohu, který lze zohlednit úpravou CTM stejně jako s obrázky.

Následující kód ukazuje, jak nakreslit text do PDF:

//data buffer to hold the PDF
NSMutableData data = new NSMutableData ();

//create a PDF with empty rectangle, which will configure it for 8.5x11 inches
UIGraphics.BeginPDFContext (data, CGRect.Empty, null);

//start a PDF page
UIGraphics.BeginPDFPage ();

using (CGContext g = UIGraphics.GetCurrentContext ()) {
    g.ScaleCTM (1, -1);
    g.TranslateCTM (0, -25);
    g.SelectFont ("Helvetica", 25, CGTextEncoding.MacRoman);
    g.ShowText ("Hello Core Graphics");
    }

//complete a PDF page
UIGraphics.EndPDFContent ();

Výsledný text se nakreslí do PDF, který je pak obsažen v NSData souboru, který lze uložit, nahrát, poslat e-mailem atd.

Souhrn

V tomto článku jsme se podívali na možnosti grafiky poskytované prostřednictvím architektury Core Graphics . Viděli jsme, jak pomocí základní grafiky kreslit geometrii, obrázky a soubory PDF v kontextu UIView, i na kontexty grafiky založené na paměti.