CGContext dans iOS — ce que c'est, méthodes et comment gérer le contexte de dessin

Auteur : IT Sectr Publié le : 2026-07-21 Temps de lecture : 9 min

CGContext est l'objet principal de Core Graphics pour exécuter des commandes de dessin 2D dans iOS et macOS. Il représente un contexte graphique qui stocke l'état actuel : couleur de remplissage, épaisseur de trait, transformation, zone de découpage et polices. Toutes les opérations de dessin — lignes, rectangles, texte, images — sont effectuées via CGContext. Selon Apple Developer Documentation, 2026, CGContext est le fondement de tous les graphiques raster et vectoriels dans l'écosystème Apple.

Points Clés

  • CGContext est le contexte graphique à travers lequel toutes les commandes 2D de Core Graphics sont exécutées.
  • setStrokeColor et setFillColor gèrent la couleur des lignes et des remplissages dans le contexte.
  • addPath et drawPath permettent de dessiner des contours CGPath arbitraires.
  • clip(to:) définit la zone de découpage pour restreindre le dessin à une zone spécifique.
  • saveGState et restoreGState sauvegardent et restaurent la pile d'états du contexte.

Qu'est-ce que CGContext ?

CGContext est un type opaque du framework Core Graphics qui représente un environnement pour exécuter des commandes de rendu 2D. Il gère la pile d'états, l'espace colorimétrique actuel, la transformation des coordonnées et la zone de découpage. CGContext est le seul objet avec lequel toutes les fonctions de dessin Quartz 2D interagissent — toute opération graphique passe par lui.

CGContext existe en plusieurs variétés selon son objectif : bitmap context pour travailler avec des images raster en mémoire, PDF context pour générer des documents PDF, window context pour le dessin à l'écran (fourni par UIView dans draw(_:)). Les développeurs iOS travaillent le plus souvent avec un contexte obtenu à partir de UIGraphicsGetCurrentContext() dans la méthode draw(_:) ou de UIGraphicsBeginImageContextWithOptions pour le rendu hors ligne.

Le contexte applique tous les paramètres via une pile d'états — le développeur peut sauvegarder l'état actuel (saveGState), modifier les paramètres et restaurer l'état précédent (restoreGState). C'est d'une importance critique lors du dessin de scènes complexes où différents éléments nécessitent différentes couleurs, épaisseurs de trait et transformations. Selon Apple WWDC 2023, une utilisation appropriée de la pile d'états améliore la lisibilité du code et prévient les artefacts visuels.

Gestion d'état : saveGState et restoreGState

CGContextSaveGState place une copie de l'état actuel du contexte sur la pile. Cet état inclut tous les paramètres : couleurs, épaisseur de trait, transformation, ombres, zone de découpage, polices. Après modification des paramètres, l'appel à CGContextRestoreGState ramène le contexte à l'état sauvegardé, annulant toutes les modifications intermédiaires. La pile peut contenir jusqu'à 32 états sur iOS.

Utilisation Pratique de la Pile

Lors du dessin de groupes d'éléments avec différents styles (par exemple, des secteurs de graphique multicolores), la pile d'états élimine la nécessité de mémoriser et restaurer manuellement chaque paramètre. Sans saveGState/restoreGState, le développeur devrait réinitialiser la couleur, l'ombre et la transformation après chaque élément. L'utilisation de la pile réduit le code et prévient les erreurs de restauration.

Il est important de maintenir un équilibre des sauvegardes et restaurations — chaque saveGState doit avoir un restoreGState correspondant. Rompre l'équilibre entraîne des fuites d'état ou une restauration prématurée, provoquant un rendu imprévisible. L'analyseur statique de Xcode ne vérifie pas l'équilibre de la pile CGContext, donc l'exactitude relève de la responsabilité du développeur. Il est recommandé de regrouper les paires dans des blocs do/finally.

swift
override func draw(_ rect: CGRect) {
    guard let ctx = UIGraphicsGetCurrentContext() else { return }

    ctx.saveGState()
    ctx.setStrokeColor(UIColor.red.cgColor)
    ctx.setLineWidth(3)
    ctx.addRect(CGRect(x: 50, y: 50, width: 200, height: 100))
    ctx.strokePath()
    ctx.restoreGState()
}

Couleurs et Remplissages

CGContextSetFillColorWithColor définit la couleur de remplissage pour les opérations suivantes. La couleur est passée en tant que CGColorRef, qui contient des informations sur l'espace colorimétrique et les composantes de couleur. CGContextSetStrokeColorWithColor fonctionne de manière similaire pour la couleur de trait. Apple recommande de mettre en cache les valeurs CGColorRef fréquemment utilisées pour améliorer les performances.

Dégradés dans CGContext

CGContextDrawLinearGradient dessine un dégradé linéaire entre deux points avec des couleurs spécifiées. CGContextDrawRadialGradient crée un dégradé radial passant d'un cercle à un autre. Pour travailler avec des dégradés, un objet CGGradientRef est d'abord créé contenant un tableau de couleurs et de positions d'arrêt. Les dégradés dans CGContext prennent en charge les espaces colorimétriques RVB et Niveaux de Gris.

Remplir une zone avec un dégradé nécessite d'abord de définir une zone de découpage. Sans clip, le dégradé remplit tout le contexte, pas seulement la forme souhaitée. Le motif typique : ajouter un chemin au contexte, appeler clip pour restreindre la zone, puis dessiner le dégradé. Ce motif est utilisé dans toutes les applications nécessitant des remplissages dégradés de formes complexes, des boutons aux arrière-plans.

FonctionObjectifEspace colorimétrique
setFillColorDéfinit la couleur de remplissageQuelconque (via CGColor)
setStrokeColorDéfinit la couleur de traitQuelconque (via CGColor)
drawLinearGradientDessine un dégradé linéaireRVB ou Niveaux de Gris
drawRadialGradientDessine un dégradé radialRVB ou Niveaux de Gris

Dessin de Chemins et de Lignes

CGContextAddPath ajoute un CGPathRef préalablement créé au contexte pour le rendu ultérieur. Après avoir ajouté un chemin, il peut être tracé (strokePath), rempli (fillPath) ou les deux. CGContextBeginPath commence un nouveau chemin, effaçant le précédent. Le contexte ne prend en charge qu'un seul chemin actif à la fois.

Lignes Droites et Courbes par Points

CGContextMoveToPoint déplace le point de contour actuel vers les coordonnées spécifiées. CGContextAddLineToPoint dessine une ligne droite du point actuel au point donné. CGContextAddCurveToPoint ajoute une courbe de Bézier cubique, CGContextAddQuadCurveToPoint ajoute une courbe quadratique. CGContextClosePath ferme le contour avec une ligne droite entre le dernier et le premier point.

Contrairement à UIBezierPath, où toutes ces méthodes sont appelées sur l'objet chemin, dans CGContext elles sont appelées directement sur le contexte. Cette différence est importante lors du choix d'une approche : UIBezierPath est plus pratique pour réutiliser les chemins, CGContext est meilleur pour un dessin unique avec une surcharge minimale. CGContext prend également en charge les lignes pointillées via CGContextSetLineDash, les extrémités flexibles via CGContextSetLineCap et les jonctions via CGContextSetLineJoin.

swift
let ctx = UIGraphicsGetCurrentContext()!
ctx.beginPath()
ctx.moveTo(x: 50, y: 100)
ctx.addLineTo(x: 200, y: 100)
ctx.addCurveTo(x1: 250, y1: 50, x2: 300, y2: 150, x3: 350, y3: 100)
ctx.setStrokeColor(UIColor.blue.cgColor)
ctx.setLineWidth(5)
ctx.strokePath()

Zone de Découpage et Transformations

CGContextClip restreint la zone de dessin au chemin actuel. Toutes les opérations de dessin ultérieures ne seront visibles qu'à l'intérieur de cette zone. C'est le mécanisme de base pour le masquage, l'arrondi des coins et la création de limites personnalisées d'éléments. La zone de découpage est également sauvegardée et restaurée via saveGState/restoreGState.

Transformations de Coordonnées

CGContextTranslateCTM déplace l'origine du système de coordonnées du contexte. CGContextScaleCTM met à l'échelle les axes X et Y. CGContextRotateCTM fait pivoter le système de coordonnées autour de l'origine actuelle. Les transformations s'accumulent — chacune est appliquée par rapport au système de coordonnées actuel. Les transformations composites (translation + rotation + échelle) sont utilisées pour l'animation et le positionnement des éléments.

Combiner le découpage et les transformations offre des capacités puissantes : vous pouvez dessiner un masque complexe via le découpage, puis appliquer une transformation à tout le contenu. Un exemple typique est l'affichage d'une partie d'image en angle avec des coins arrondis. L'ordre des opérations est important : d'abord définir la zone de découpage, puis appliquer la transformation, puis dessiner le contenu. Apple recommande de minimiser les changements de CTM (Matrice de Transformation Courante) dans la boucle de dessin.

swift
override func draw(_ rect: CGRect) {
    guard let ctx = UIGraphicsGetCurrentContext() else { return }
    ctx.saveGState()

    // clipping region - circle
    ctx.addEllipse(in: CGRect(x: 50, y: 50, width: 200, height: 200))
    ctx.clip()

    // content transformation
    ctx.translateBy(x: 150, y: 150)
    ctx.rotate(by: .pi / 4)
    ctx.translateBy(x: -150, y: -150)

    UIImage(named: "photo")?.draw(at: CGPoint(x: 50, y: 50))
    ctx.restoreGState()
}

Exemple de Dessin dans CGContext

Examinons un exemple complet de création d'un graphique dégradé avec CGContext. Le graphique comprend trois secteurs de différentes couleurs avec des remplissages dégradés et des étiquettes de texte. Le code démontre la combinaison de saveGState, clip, dégradés et rendu de texte dans un seul contexte.

swift
class PieChartView: UIView {

    private struct Slice {
        let color: UIColor
        let value: CGFloat
        let label: String
    }

    override func draw(_ rect: CGRect) {
        guard let ctx = UIGraphicsGetCurrentContext() else { return }

        let slices = [
            Slice(color: .systemRed, value: 0.4, label: "iOS"),
            Slice(color: .systemGreen, value: 0.35, label: "Android"),
            Slice(color: .systemBlue, value: 0.25, label: "Other")
        ]

        let center = CGPoint(x: bounds.midX, y: bounds.midY)
        let radius = bounds.width * 0.35
        var startAngle: CGFloat = -.pi / 2

        for slice in slices {
            let endAngle = startAngle + .pi * 2 * slice.value

            ctx.saveGState()
            ctx.moveTo(x: center.x, y: center.y)
            ctx.addArc(center: center, radius: radius,
                       startAngle: startAngle, endAngle: endAngle, clockwise: false)
            ctx.closePath()
            ctx.setFillColor(slice.color.cgColor)
            ctx.fillPath()

            // text label
            let midAngle = startAngle + endAngle / 2
            let labelPos = CGPoint(
                x: center.x + radius * 0.7 * cos(midAngle),
                y: center.y + radius * 0.7 * sin(midAngle)
            )
            slice.label.draw(at: labelPos, withAttributes: [
                .foregroundColor: UIColor.white,
                .font: UIFont.boldSystemFont(ofSize: 14)
            ])
            ctx.restoreGState()
            startAngle = endAngle
        }
    }
}

Dans cet exemple, chaque secteur du graphique est dessiné dans son propre bloc saveGState/restoreGState. Cette approche garantit que les paramètres de couleur et de chemin d'un secteur n'affectent pas les autres. La méthode addArc crée un arc de l'angle de début à l'angle de fin, et closePath ferme le secteur vers le centre. Le texte de l'étiquette est placé à l'angle médian du secteur en utilisant les fonctions trigonométriques cos et sin pour le calcul de la position.

Pour améliorer les performances lors des redessins fréquents, il est recommandé de mettre en cache les calculs d'angles et de positions dans un tableau séparé. CGContext exécute toutes les opérations sur le CPU, donc les scènes complexes avec des dizaines de secteurs peuvent nécessiter une optimisation — par exemple, le pré-rendu dans CGLayer ou l'utilisation de Metal pour l'accélération GPU. Pour la plupart des tâches d'interface utilisateur avec 5 à 10 éléments, les performances de CGContext restent acceptables.

Questions Fréquentes

Comment obtenir le CGContext actuel dans iOS ?

Appelez UIGraphicsGetCurrentContext() à l'intérieur de la méthode draw(_:) de UIView ou à l'intérieur d'un bloc UIGraphicsBeginImageContextWithOptions. Pour les couches CALayer, utilisez la méthode draw(in:) de CALayerDelegate, qui reçoit un contexte prêt.

Quelle est la différence entre fillPath et strokePath ?

fillPath remplit l'intérieur du chemin actuel avec la couleur de setFillColor. strokePath dessine une ligne le long du chemin avec les paramètres de setStrokeColor, setLineWidth et setLineCap. Les deux opérations sont exécutées séquentiellement : d'abord le remplissage, puis le trait si nécessaire.

Qu'est-ce qu'un bitmap CGContext ?

Bitmap CGContext est un contexte créé via CGBitmapContextCreate qui dessine dans un tampon mémoire au lieu de l'écran. Il est utilisé pour la génération d'images en arrière-plan, le traitement graphique sans affichage et la création de textures pour Metal ou OpenGL.

Comment réinitialiser tous les paramètres de CGContext ?

Core Graphics ne fournit pas de méthode pour réinitialiser tous les paramètres. Utilisez saveGState avant les modifications et restoreGState pour revenir à l'état d'origine. Alternativement, créez un nouveau contexte avec les mêmes paramètres.

Pourquoi le dégradé ne s'affiche-t-il pas à l'intérieur de la forme ?

Avant d'appeler drawLinearGradient, définissez la zone de découpage via clip sur le chemin souhaité. Sans clip, le dégradé remplit tout le contexte. Ordre : addPath → clip → drawLinearGradient — garantit le dégradé à l'intérieur de la forme.

Résumé

  • CGContext est l'objet central de Core Graphics pour toutes les opérations de dessin 2D sur iOS et macOS.
  • saveGState et restoreGState gèrent la pile d'états du contexte, évitant les effets secondaires.
  • setFillColor et setStrokeColor définissent les couleurs de remplissage et de trait via CGColorRef.
  • addPath, strokePath, fillPath travaillent avec des contours CGPath arbitraires.
  • clip restreint la zone de dessin au chemin actuel pour les masques et les arrondis.
  • translateCTM, scaleCTM, rotateCTM transforment le système de coordonnées du contexte.
  • Toutes les opérations CGContext s'exécutent sur le CPU — pour les graphiques complexes, utilisez CGLayer ou Metal.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi