Partager via


Graphiques de base dans Xamarin.iOS

Cet article décrit les frameworks iOS Core Graphics. Il montre comment utiliser Core Graphics pour dessiner la géométrie, les images et les fichiers PDF.

iOS inclut l’infrastructure Core Graphics pour fournir une prise en charge de dessin de bas niveau. Ces frameworks permettent les fonctionnalités graphiques enrichies dans UIKit.

Core Graphics est une infrastructure graphique 2D de bas niveau qui permet de dessiner des graphiques indépendants de l’appareil. Tout le dessin 2D dans UIKit utilise Core Graphics en interne.

Core Graphics prend en charge le dessin dans un certain nombre de scénarios, notamment :

Espace géométrique

Quel que soit le scénario, tous les dessins effectués avec Core Graphics sont effectués dans l’espace géométrique, ce qui signifie qu’il fonctionne en points abstraits plutôt que en pixels. Vous décrivez ce que vous souhaitez dessiner en termes de géométrie et d’état de dessin, tels que les couleurs, les styles de trait, etc. et les poignées Core Graphics qui traduisent tout en pixels. Un tel état est ajouté à un contexte graphique, que vous pouvez considérer comme le canevas d’un peintre.

Cette approche présente quelques avantages :

  • Le code de dessin devient dynamique et peut par la suite modifier des graphiques au moment de l’exécution.
  • La réduction de la nécessité d’images statiques dans le bundle d’applications peut réduire la taille de l’application.
  • Les graphiques deviennent plus résilients aux modifications de résolution sur les appareils.

Dessin dans une sous-classe UIView

Chaque UIView méthode est Draw appelée par le système lorsqu’elle doit être dessinée. Pour ajouter du code de dessin à une vue, sous-classe UIView et remplacement Draw:

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

Le dessin ne doit jamais être appelé directement. Il est appelé par le système pendant le traitement de la boucle d’exécution. La première fois par le biais de la boucle d’exécution après l’ajout d’une vue à la hiérarchie d’affichage, sa Draw méthode est appelée. Les appels suivants se Draw produisent lorsque l’affichage est marqué comme nécessitant d’être dessiné en appelant ou SetNeedsDisplaySetNeedsDisplayInRect sur l’affichage.

Modèle pour le code graphique

Le code de l’implémentation Draw doit décrire ce qu’il souhaite dessiner. Le code de dessin suit un modèle dans lequel il définit un état de dessin et appelle une méthode pour demander qu’elle soit dessinée. Ce modèle peut être généralisé comme suit :

  1. Obtenir un contexte graphique.

  2. Configurez les attributs de dessin.

  3. Créez une géométrie à partir de primitives de dessin.

  4. Appelez une méthode Draw ou Stroke.

Exemple de dessin de base

Par exemple, prenons l’extrait de code suivant :

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

Nous allons décomposer ce code :

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

Avec cette ligne, il obtient d’abord le contexte graphique actuel à utiliser pour le dessin. Vous pouvez considérer un contexte graphique comme le canevas sur lequel le dessin se produit, contenant tout l’état du dessin, tel que le trait et les couleurs de remplissage, ainsi que la géométrie à dessiner.

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

Après avoir obtenu un contexte graphique, le code configure certains attributs à utiliser lors du dessin, illustré ci-dessus. Dans ce cas, la largeur de ligne, le trait et les couleurs de remplissage sont définis. Tout dessin suivant utilise ensuite ces attributs, car ils sont conservés dans l’état du contexte graphique.

Pour créer la géométrie, le code utilise un CGPathchemin d’accès graphique à décrire à partir de lignes et de courbes. Dans ce cas, le chemin ajoute des lignes qui connectent un tableau de points pour constituer un triangle. Comme indiqué ci-dessous, Core Graphics utilise un système de coordonnées pour le dessin d’affichage, où l’origine se trouve en haut à gauche, avec un x direct positif vers la droite et la direction positive-y vers le bas :

var path = new CGPath ();

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

path.CloseSubpath ();

Une fois le chemin d’accès créé, il est ajouté au contexte graphique afin que l’appel AddPath et DrawPath puisse le dessiner respectivement.

L’affichage obtenu est illustré ci-dessous :

L’exemple de triangle de sortie

Création de remplissages dégradés

Des formes de dessin plus riches sont également disponibles. Par exemple, Core Graphics permet de créer des remplissages dégradés et d’appliquer des chemins de découpage. Pour dessiner un remplissage dégradé à l’intérieur du chemin d’accès de l’exemple précédent, le chemin d’accès doit d’abord être défini comme chemin de découpage :

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

La définition du chemin d’accès actuel en tant que chemin de découpage limite tout dessin suivant dans la géométrie du chemin, tel que le code suivant, qui dessine un dégradé linéaire :

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

Ces modifications produisent un remplissage dégradé, comme indiqué ci-dessous :

Exemple avec un remplissage dégradé

Modification des modèles de ligne

Les attributs de dessin des lignes peuvent également être modifiés avec Core Graphics. Cela inclut la modification de la largeur de ligne et de la couleur de trait, ainsi que le motif de trait lui-même, comme indiqué dans le code suivant :

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

L’ajout de ce code avant toute opération de dessin entraîne des traits pointillés de 10 unités de long, avec 4 unités d’espacement entre tirets, comme indiqué ci-dessous :

L’ajout de ce code avant toutes les opérations de dessin entraîne des traits en pointillés

Notez que lors de l’utilisation de l’API unifiée dans Xamarin.iOS, le type de tableau doit être un nfloatet doit également être explicitement converti en Math.PI.

Dessin d’images et de texte

Outre les chemins de dessin dans le contexte graphique d’une vue, Core Graphics prend également en charge le dessin d’images et de texte. Pour dessiner une image, créez simplement une CGImage image et passez-la à un DrawImage appel :

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

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

Toutefois, cela produit une image dessinée à l’envers, comme indiqué ci-dessous :

Image dessinée à l’envers

La raison pour laquelle il s’agit de Core Graphics origin for image drawing se trouve en bas à gauche, tandis que la vue a son origine dans le coin supérieur gauche. Par conséquent, pour afficher correctement l’image, l’origine doit être modifiée, ce qui peut être effectué en modifiant la matrice de transformation actuelle (CTM). La CTM définit l’emplacement où les points vivent, également appelés espace utilisateur. Inverser la CTM dans la direction y et la déplacer par la hauteur des limites dans la direction y négative peut retourner l’image.

Le contexte graphique a des méthodes d’assistance pour transformer la CTM. Dans ce cas, ScaleCTM « retourne » le dessin et TranslateCTM le déplace vers le coin supérieur gauche, comme indiqué ci-dessous :

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

L’image résultante s’affiche ensuite verticalement :

L’exemple d’image affiché verticalement

Important

Les modifications apportées au contexte graphique s’appliquent à toutes les opérations de dessin suivantes. Par conséquent, lorsque la CTM est transformée, elle affecte tout dessin supplémentaire. Par exemple, si vous avez dessiné le triangle après la transformation CTM, il apparaît à l’envers.

Ajout de texte à l’image

Comme pour les chemins d’accès et les images, le dessin de texte avec Core Graphics implique le même modèle de base de définition d’un état graphique et l’appel d’une méthode à dessiner. Dans le cas du texte, la méthode d’affichage du texte est ShowText. Lorsqu’il est ajouté à l’exemple de dessin d’image, le code suivant dessine du texte à l’aide de Core Graphics :

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

Comme vous pouvez le voir, la définition de l’état graphique du dessin de texte est similaire à la géométrie de dessin. Toutefois, pour le dessin de texte, le mode dessin de texte et la police sont également appliqués. Dans ce cas, une ombre est également appliquée, bien que l’application d’ombres fonctionne de la même façon pour le dessin de chemin d’accès.

Le texte obtenu s’affiche avec l’image, comme indiqué ci-dessous :

Le texte obtenu s’affiche avec l’image

Images sauvegardées en mémoire

Outre le dessin dans le contexte graphique d’une vue, Core Graphics prend en charge le dessin d’images sauvegardées en mémoire, également appelées dessin hors écran. Pour ce faire, vous devez :

  • Création d’un contexte graphique soutenu par une bitmap en mémoire
  • Définition de l’état du dessin et émission de commandes de dessin
  • Obtention de l’image à partir du contexte
  • Suppression du contexte

Contrairement à la Draw méthode, où le contexte est fourni par la vue, dans ce cas, vous créez le contexte de l’une des deux manières suivantes :

  1. En appelant UIGraphics.BeginImageContext (ou BeginImageContextWithOptions)

  2. En créant un nouveau CGBitmapContextInstance

CGBitmapContextInstance est utile lorsque vous travaillez directement avec les bits d’image, tels que pour les cas où vous utilisez un algorithme de manipulation d’image personnalisé. Dans tous les autres cas, vous devez utiliser BeginImageContext ou BeginImageContextWithOptions.

Une fois que vous avez un contexte d’image, l’ajout de code de dessin est tout comme dans une UIView sous-classe. Par exemple, l’exemple de code utilisé précédemment pour dessiner un triangle peut être utilisé pour dessiner sur une image en mémoire au lieu d’un UIView, comme illustré ci-dessous :

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

Une utilisation courante du dessin vers une bitmap en mémoire est de capturer une image à partir de n’importe quel UIView. Par exemple, le code suivant restitue la couche d’une vue dans un contexte bitmap et crée une UIImage image à partir de celle-ci :

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

Fichiers PDF de dessin

Outre les images, Core Graphics prend en charge le dessin PDF. Comme les images, vous pouvez afficher un FICHIER PDF en mémoire, ainsi que lire un FICHIER PDF pour le rendu dans un UIViewfichier .

PDF dans un UIView

Core Graphics prend également en charge la lecture d’un fichier PDF et son rendu dans une vue à l’aide de la CGPDFDocument classe. La CGPDFDocument classe représente un fichier PDF dans le code et peut être utilisée pour lire et dessiner des pages.

Par exemple, le code suivant dans une UIView sous-classe lit un FICHIER PDF à partir d’un fichier dans un CGPDFDocumentfichier :

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)
    {
        ...
    }
}

La Draw méthode peut ensuite utiliser la CGPDFDocument méthode pour lire une page CGPDFPage et la restituer en appelant DrawPDFPage, comme indiqué ci-dessous :

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

PDF sauvegardé en mémoire

Pour un fichier PDF en mémoire, vous devez créer un contexte PDF en appelant BeginPDFContext. Le dessin au format PDF est granulaire aux pages. Chaque page est démarrée en appelant BeginPDFPage et terminée en appelant EndPDFContent, avec le code graphique entre deux. En outre, comme avec le dessin d’images, le dessin PDF en mémoire soutenu utilise une origine en bas à gauche, qui peut être comptabilisée en modifiant la CTM comme avec des images.

Le code suivant montre comment dessiner du texte dans un fichier 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 ();

Le texte obtenu est dessiné au format PDF, qui est ensuite contenu dans un NSData fichier qui peut être enregistré, chargé, envoyé par e-mail, etc.

Résumé

Dans cet article, nous avons examiné les fonctionnalités graphiques fournies via l’infrastructure Core Graphics . Nous avons vu comment utiliser Core Graphics pour dessiner la géométrie, les images et les fichiers PDF dans le contexte d’un UIView, contexte graphique ainsi que dans des contextes graphiques soutenus en mémoire.