CGContext in iOS — wat is het, methoden en hoe de tekencontext te beheren

Auteur: IT Sectr Gepubliceerd: 2026-07-21 Leestijd: 9 min

CGContext — het belangrijkste Core Graphics-object voor het uitvoeren van 2D-tekenopdrachten in iOS en macOS. Het vertegenwoordigt een grafische context die de huidige status opslaat: vulkleur, lijndikte, transformatie, knipgebied en lettertypen. Alle tekenbewerkingen — lijnen, rechthoeken, tekst, afbeeldingen — worden uitgevoerd via CGContext. Volgens Apple Developer Documentation, 2026 is CGContext de basis van alle raster- en vectorgraphics in het Apple-ecosysteem.

Belangrijkste

  • CGContext — de grafische context waarlangs alle 2D Core Graphics-opdrachten worden uitgevoerd.
  • setStrokeColor en setFillColor beheren de kleur van lijnen en vullingen in de context.
  • addPath en drawPath maken het tekenen van willekeurige CGPath-contouren mogelijk.
  • clip(to:) stelt het knipgebied in om het tekenen tot een specifieke zone te beperken.
  • saveGState en restoreGState slaan de statusstack van de context op en herstellen deze.

Wat is CGContext?

CGContext — een ondoorzichtig type (opaque type) uit het Core Graphics-framework dat een omgeving vertegenwoordigt voor het uitvoeren van 2D-renderingopdrachten. Het beheert de statusstack, de huidige kleurruimte, de coördinatentransformatie en het knipgebied. CGContext is het enige object waarmee alle Quartz 2D-tekenfuncties interageren — alle grafische bewerkingen verlopen via dit object.

CGContext bestaat in verschillende varianten afhankelijk van het doel: bitmap context voor het werken met rasterafbeeldingen in het geheugen, PDF context voor het genereren van PDF-documenten, window context voor weergave op het scherm (geleverd door UIView in draw(_:)). In iOS werken ontwikkelaars meestal met de context verkregen uit UIGraphicsGetCurrentContext() binnen de methode draw(_:) of uit UIGraphicsBeginImageContextWithOptions voor offline rendering.

De context past alle instellingen toe via de statusstack — de ontwikkelaar kan de huidige status opslaan (saveGState), parameters wijzigen en de vorige status herstellen (restoreGState). Dit is van cruciaal belang bij het renderen van complexe scènes waar verschillende elementen verschillende kleuren, lijndiktes en transformaties vereisen. Volgens Apple WWDC 2023 verbetert correct gebruik van de statusstack de leesbaarheid van de code en voorkomt het visuele artefacten.

Statusbeheer: saveGState en restoreGState

CGContextSaveGState plaatst een kopie van de huidige status van de context op de stack. Deze status omvat alle instellingen: kleuren, lijndikte, transformatie, schaduwen, knipgebied, lettertypen. Na het wijzigen van parameters herstelt de aanroep CGContextRestoreGState de context naar de opgeslagen status, waarbij alle tussentijdse wijzigingen ongedaan worden gemaakt. De stack kan maximaal 32 statussen bevatten op iOS.

Praktische toepassing van de stack

Bij het tekenen van een groep elementen met verschillende stijlen (bijvoorbeeld de gekleurde sectoren van een diagram) elimineert de statusstack de noodzaak om elke parameter handmatig te onthouden en te herstellen. Zonder saveGState/restoreGState zou de ontwikkelaar na elk element de kleur, schaduw en transformatie opnieuw moeten instellen. Gebruik van de stack verkort de code en elimineer herstellingsfouten.

Het is belangrijk om de balans tussen opslaan en herstellen te bewaren — elke saveGState moet een bijbehorende restoreGState hebben. Een verstoorde balans leidt tot lekkende statussen of voortijdig herstellen, wat onvoorspelbare weergave veroorzaakt. De statische analysator van Xcode controleert de balans van de CGContext-stack niet, dus de verantwoordelijkheid voor correctheid ligt bij de ontwikkelaar. Het wordt aanbevolen om paren te groeperen in do/finally-blokken.

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

Kleuren en vullingen

CGContextSetFillColorWithColor stelt de vulkleur in voor volgende bewerkingen. De kleur wordt doorgegeven als CGColorRef, die informatie bevat over de kleurruimte en kleurcomponenten. CGContextSetStrokeColorWithColor werkt analoog voor de lijnkleur. Apple raadt aan om veelgebruikte CGColorRef-objecten te cachen voor betere prestaties.

Gradiënten in CGContext

CGContextDrawLinearGradient tekent een lineair verlooppatroon tussen twee punten met opgegeven kleuren. CGContextDrawRadialGradient creëert een radiaal verlooppatroon dat van de ene cirkel naar de andere overgaat. Om met gradiënten te werken, wordt eerst een CGGradientRef-object gemaakt dat een reeks kleuren en stopposities bevat. Gradiënten in CGContext ondersteunen zowel RGB- als Grayscale-kleurruimten.

Het vullen van een gebied met een gradiënt vereist het vooraf instellen van het knipgebied. Zonder clip vult de gradiënt de hele context, niet alleen de gewenste vorm. Het typische patroon: voeg een pad toe aan de context, roep clip aan om het gebied te beperken, teken vervolgens de gradiënt. Dit patroon wordt gebruikt in alle toepassingen die gradiëntvulling van complexe vormen vereisen, van knoppen tot achtergronden.

FunctieDoelKleurruimte
setFillColorStelt vulkleur inElke (via CGColor)
setStrokeColorStelt lijnkleur inElke (via CGColor)
drawLinearGradientTekent lineaire gradiëntRGB of Grayscale
drawRadialGradientTekent radiale gradiëntRGB of Grayscale

Tekenen van contouren en lijnen

CGContextAddPath voegt een eerder aangemaakte CGPathRef toe aan de context voor latere weergave. Na het toevoegen van het pad kan het worden omtrekt (strokePath), gevuld (fillPath) of beide bewerkingen. CGContextBeginPath start een nieuw pad, waarbij het vorige wordt gewist. De context ondersteunt slechts één actief pad tegelijk.

Rechte lijnen en krommen op basis van punten

CGContextMoveToPoint verplaatst het huidige punt van het pad naar de opgegeven coördinaten. CGContextAddLineToPoint tekent een rechte lijn van het huidige punt naar het opgegeven punt. CGContextAddCurveToPoint voegt een kubieke Bézier-curve toe, CGContextAddQuadCurveToPoint — een kwadratische. CGContextClosePath sluit het pad met een rechte lijn tussen het laatste en eerste punt.

In tegenstelling tot UIBezierPath, waar al deze methoden op het pad-object worden aangeroepen, worden ze in CGContext rechtstreeks op de context aangeroepen. Dit verschil is belangrijk bij het kiezen van de aanpak: UIBezierPath is handiger voor herbruikbare contouren, CGContext — voor eenmalige weergave met minimale overhead. CGContext ondersteunt ook stippellijnen via CGContextSetLineDash, flexibele uiteinden via CGContextSetLineCap en verbindingen 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()

Knipgebied en transformaties

CGContextClip beperkt het tekengebied tot het huidige pad. Alle volgende tekenbewerkingen zijn alleen binnen dit gebied zichtbaar. Dit is het basismechanisme voor maskeren, het afronden van hoeken en het maken van aangepaste elementgrenzen. Het knipgebied wordt ook opgeslagen en hersteld via saveGState/restoreGState.

Coördinatentransformatie

CGContextTranslateCTM verplaatst de oorsprong van de contextcoördinaten. CGContextScaleCTM schaalt de X- en Y-assen. CGContextRotateCTM roteert het coördinatenstelsel rond de huidige oorsprong. Transformaties worden opgestapeld — elke volgende wordt toegepast ten opzichte van het huidige coördinatenstelsel. Samengestelde transformaties (verplaatsing + rotatie + schaling) worden gebruikt voor animatie en positionering van elementen.

Gecombineerd gebruik van knippen en transformeren biedt krachtige mogelijkheden: men kan een complex masker tekenen door te knippen en vervolgens een transformatie toepassen op de hele inhoud. Een typisch voorbeeld — het weergeven van een deel van een afbeelding onder een hoek met afgeronde randen. De volgorde van bewerkingen is belangrijk: stel eerst het knipgebied in, pas dan de transformatie toe, teken vervolgens de inhoud. Apple raadt aan om het aantal CTM-wijzigingen (Current Transformation Matrix) in de renderlus te minimaliseren.

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

    // knipgebied — cirkel
    ctx.addEllipse(in: CGRect(x: 50, y: 50, width: 200, height: 200))
    ctx.clip()

    // inhoudstransformatie
    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()
}

Voorbeeld van tekenen in CGContext

Laten we een volledig voorbeeld bekijken van het maken van een gradiëntdiagram met CGContext. Het diagram omvat drie sectoren van verschillende kleuren met gradiëntvulling en tekstlabels. De code demonstreert een combinatie van saveGState, clip, gradiënten en tekstweergave in één context.

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

            // tekstlabel
            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
        }
    }
}

In dit voorbeeld wordt elke sector van het diagram getekend in zijn eigen saveGState/restoreGState-blok. Deze aanpak garandeert dat de kleur- en padinstellingen van de ene sector de andere niet beïnvloeden. De methode addArc creëert een boog van de begin- naar de eindhoek, closePath sluit de sector naar het midden. Het tekstlabel wordt op de middellijn van de sectorhoek geplaatst met behulp van de trigonometrische functies cos en sin voor positieberekening.

Om de prestaties bij veelvuldig hertekenen te verbeteren, wordt aanbevolen om de berekeningen van hoeken en posities in een aparte array te cachen. CGContext voert alle bewerkingen op de CPU uit, dus complexe scènes met tientallen sectoren kunnen optimalisatie vereisen — bijvoorbeeld voorafgaande rastering in CGLayer of gebruik van Metal voor GPU-versnelling. Voor de meeste UI-taken met 5–10 elementen blijft de CGContext-prestatie acceptabel.

Veelgestelde vragen

Hoe krijg ik de huidige CGContext in iOS?

Roep UIGraphicsGetCurrentContext() aan binnen de methode draw(_:) van UIView of binnen het UIGraphicsBeginImageContextWithOptions-blok. Gebruik voor CALayer-lagen draw(in:) van de CALayerDelegate, die een kant-en-klare context ontvangt.

Wat is het verschil tussen fillPath en strokePath?

fillPath vult het binnengebied van het huidige pad met de kleur uit setFillColor. strokePath tekent een lijn langs het pad met de parameters setStrokeColor, setLineWidth en setLineCap. Beide bewerkingen worden opeenvolgend uitgevoerd: eerst fill, daarna stroke indien nodig.

Wat is bitmap CGContext?

Bitmap CGContext — een context aangemaakt via CGBitmapContextCreate die in een geheugenbuffer tekent in plaats van op het scherm. Wordt gebruikt voor het genereren van afbeeldingen op de achtergrond, grafische verwerking zonder weergave en het maken van textures voor Metal of OpenGL.

Hoe reset ik alle CGContext-instellingen?

Core Graphics biedt geen methode om alle instellingen te resetten. Gebruik saveGState vóór wijzigingen en restoreGState om terug te keren naar de oorspronkelijke status. Als alternatief kunt u een nieuwe context met dezelfde parameters aanmaken.

Waarom wordt de gradiënt niet binnen de vorm weergegeven?

Stel vóór het aanroepen van drawLinearGradient het knipgebied in via clip op het gewenste pad. Zonder clip vult de gradiënt de hele context. Volgorde: addPath → clip → drawLinearGradient — garandeert de gradiënt binnen de vorm.

Samenvatting

  • CGContext — het centrale Core Graphics-object voor alle 2D-tekenbewerkingen op iOS en macOS.
  • saveGState en restoreGState beheren de statusstack van de context en voorkomen neveneffecten.
  • setFillColor en setStrokeColor stellen vul- en lijnkleuren in via CGColorRef.
  • addPath, strokePath, fillPath werken met willekeurige CGPath-contouren.
  • clip beperkt het tekengebied tot het huidige pad voor maskers en afrondingen.
  • translateCTM, scaleCTM, rotateCTM transformeren het coördinatenstelsel van de context.
  • Alle CGContext-bewerkingen worden op de CPU uitgevoerd — gebruik voor complexe graphics CGLayer of Metal.

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook