CGContext i iOS — vad är det, metoder och hur man hanterar ritkontexten

Författare: IT Sectr Publicerad: 2026-07-21 Lästid: 9 min

CGContext — huvudobjektet i Core Graphics för att utföra 2D-ritkommandon i iOS och macOS. Det representerar en grafisk kontext som lagrar det aktuella tillståndet: fyllningsfärg, linjetjocklek, transformation, klippområde och typsnitt. Alla ritoperationer — linjer, rektanglar, text, bilder — utförs via CGContext. Enligt Apple Developer Documentation, 2026 är CGContext grunden för all raster- och vektorgrafik i Apples ekosystem.

Huvudpunkter

  • CGContext — den grafiska kontext genom vilken alla 2D-kommandon i Core Graphics utförs.
  • setStrokeColor och setFillColor hanterar färgen på linjer och fyllningar i kontexten.
  • addPath och drawPath gör det möjligt att rita godtyckliga CGPath-konturer.
  • clip(to:) anger klippområdet för att begränsa ritning till en specifik zon.
  • saveGState och restoreGState sparar och återställer kontextens tillståndsstack.

Vad är CGContext?

CGContext — en ogenomskinlig typ (opaque type) från Core Graphics-ramverket som representerar en miljö för att utföra 2D-renderingskommandon. Den hanterar tillståndsstacken, det aktuella färgrymden, koordinattransformation och klippområde. CGContext är det enda objekt som alla Quartz 2D-ritfunktioner interagerar med — alla grafiska operationer går igenom det.

CGContext finns i flera varianter beroende på syfte: bitmap context för arbete med rasterbilder i minnet, PDF context för att generera PDF-dokument, window context för rendering på skärmen (tillhandahålls av UIView i draw(_:)). I iOS arbetar utvecklare oftast med kontexten som erhålls från UIGraphicsGetCurrentContext() inuti metoden draw(_:) eller från UIGraphicsBeginImageContextWithOptions för offline-rendering.

Kontexten tillämpar alla inställningar via tillståndsstacken — utvecklaren kan spara det aktuella tillståndet (saveGState), ändra parametrar och återställa det föregående (restoreGState). Detta är kritiskt vid ritning av komplexa scener där olika element kräver olika färger, linjetjocklekar och transformationer. Enligt Apple WWDC 2023 förbättrar korrekt användning av tillståndsstacken kodläsbarheten och förhindrar visuella artefakter.

Tillståndshantering: saveGState och restoreGState

CGContextSaveGState placerar en kopia av kontextens aktuella tillstånd i stacken. Detta tillstånd inkluderar alla inställningar: färger, linjetjocklek, transformation, skuggor, klippområde, typsnitt. Efter modifiering av parametrar återställer anropet CGContextRestoreGState kontexten till det sparade tillståndet och ångrar alla mellanliggande ändringar. Stacken kan innehålla upp till 32 tillstånd på iOS.

Praktisk tillämpning av stacken

Vid ritning av en grupp element med olika stilar (t.ex. flerfärgade sektorer i ett diagram) eliminerar tillståndsstacken behovet av att manuellt komma ihåg och återställa varje parameter. Utan saveGState/restoreGState skulle utvecklaren behöva återställa färg, skugga och transformation efter varje element. Användning av stacken minskar koden och eliminerar återställningsfel.

Det är viktigt att upprätthålla balans mellan sparanden och återställanden — varje saveGState måste ha en matchande restoreGState. Brott mot balansen leder till tillståndsläckage eller förtida återställning, vilket orsakar oförutsägbar visning. Xcodes statiska analysator kontrollerar inte balansen i CGContext-stacken, så ansvaret för korrekthet ligger hos utvecklaren. Det rekommenderas att gruppera par i do/finally-block.

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

Färger och fyllningar

CGContextSetFillColorWithColor anger fyllningsfärgen för efterföljande operationer. Färgen skickas som CGColorRef, som innehåller information om färgrymd och färgkomponenter. CGContextSetStrokeColorWithColor fungerar analogt för konturfärgen. Apple rekommenderar att cachning av ofta använda CGColorRef för att förbättra prestandan.

Gradienter i CGContext

CGContextDrawLinearGradient ritar en linjär gradient mellan två punkter med angivna färger. CGContextDrawRadialGradient skapar en radiell gradient som övergår från en cirkel till en annan. För att arbeta med gradienter skapas först ett CGGradientRef-objekt som innehåller en array av färger och stoppositioner. Gradienter i CGContext stöder både RGB- och Grayscale-färgrymder.

Fyllning av ett område med gradient kräver föregående inställning av klippområdet. Utan clip fyller gradienten hela kontexten, inte bara den önskade formen. Typiskt mönster: lägg till en bana i kontexten, anropa clip för att begränsa området, rita sedan gradienten. Detta mönster används i alla applikationer som kräver gradientfyllning av komplexa former, från knappar till bakgrunder.

FunktionSyfteFärgrymd
setFillColorAnger fyllningsfärgValfritt (via CGColor)
setStrokeColorAnger konturfärgValfritt (via CGColor)
drawLinearGradientRitar linjär gradientRGB eller Grayscale
drawRadialGradientRitar radiell gradientRGB eller Grayscale

Rita konturer och linjer

CGContextAddPath lägger till en tidigare skapad CGPathRef i kontexten för efterföljande rendering. Efter att banan har lagts till kan den streckas (strokePath), fyllas (fillPath) eller båda operationerna utföras. CGContextBeginPath startar en ny bana och rensar den föregående. Kontexten stöder endast en aktiv bana åt gången.

Raka linjer och kurvor efter punkter

CGContextMoveToPoint flyttar banans aktuella punkt till angivna koordinater. CGContextAddLineToPoint ritar en rak linje från den aktuella punkten till den angivna. CGContextAddCurveToPoint lägger till en kubisk Bézierkurva, CGContextAddQuadCurveToPoint en kvadratisk. CGContextClosePath stänger banan med en rak linje mellan den sista och första punkten.

Till skillnad från UIBezierPath, där alla dessa metoder anropas på banobjektet, anropas de i CGContext direkt på kontexten. Denna skillnad är viktig vid val av tillvägagångssätt: UIBezierPath är bekvämare för återanvändning av konturer, CGContext för engångsritning med minimal overhead. CGContext stöder också streckade linjer via CGContextSetLineDash, flexibla ändar via CGContextSetLineCap och fogar 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()

Klippområde och transformationer

CGContextClip begränsar ritområdet till den aktuella konturen. Alla efterföljande ritoperationer kommer endast att vara synliga inom detta område. Detta är den grundläggande mekanismen för maskering, rundning av hörn och skapande av icke-standardiserade elementgränser. Klippområdet sparas och återställs också via saveGState/restoreGState.

Koordinattransformation

CGContextTranslateCTM förskjuter kontextens koordinatursprung. CGContextScaleCTM skalar X- och Y-axlarna. CGContextRotateCTM roterar koordinatsystemet runt det aktuella ursprunget. Transformationer ackumuleras — varje efterföljande tillämpas i förhållande till det aktuella koordinatsystemet. Sammansatta transformationer (förskjutning + rotation + skalning) används för animation och positionering av element.

Kombinerad användning av klippning och transformation ger kraftfulla möjligheter: man kan rita en komplex mask via klippning och sedan tillämpa transformation på hela innehållet. Typiskt exempel — visning av en del av en bild i vinkel med rundade hörn. Operationsordningen är viktig: först ange klippområdet, sedan tillämpa transformation, därefter rita innehållet. Apple rekommenderar att minimera antalet CTM-ändringar (Current Transformation Matrix) i renderingsloopen.

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

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

    // innehållsomvandling
    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()
}

Exempel på ritning i CGContext

Låt oss titta på ett komplett exempel på att skapa ett gradientdiagram med CGContext. Diagrammet inkluderar tre sektorer i olika färger med gradientfyllning och textetiketter. Koden demonstrerar kombinationen av saveGState, clip, gradienter och textrendering i en kontext.

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

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

I detta exempel ritas varje sektor av diagrammet i sitt eget saveGState/restoreGState-block. Detta tillvägagångssätt garanterar att färg- och baninställningarna för en sektor inte påverkar andra. Metoden addArc skapar en båge från startvinkeln till slutvinkeln, closePath stänger sektorn mot centrum. Textetiketten placeras på mittlinjen av sektorns vinkel med hjälp av trigonometriska funktioner cos och sin för att beräkna positionen.

För att förbättra prestandan vid frekvent omritning rekommenderas att cachelagra beräkningen av vinklar och positioner i en separat array. CGContext utför alla operationer på CPU:n, så komplexa scener med dussintals sektorer kan kräva optimering — till exempel förrasterisering i CGLayer eller användning av Metal för GPU-acceleration. För de flesta UI-uppgifter med 5–10 element förblir CGContext-prestandan acceptabel.

Vanliga frågor

Hur får man den aktuella CGContext i iOS?

Anropa UIGraphicsGetCurrentContext() inuti UIView-metoden draw(_:) eller inuti UIGraphicsBeginImageContextWithOptions-blocket. För CALager-lager, använd draw(in:) hos CALayerDelegate-delegaten, som får en färdig kontext.

Vad är skillnaden mellan fillPath och strokePath?

fillPath fyller det inre området av den aktuella konturen med färgen från setFillColor. strokePath ritar en linje längs konturen med parametrarna setStrokeColor, setLineWidth och setLineCap. Båda operationerna utförs sekventiellt: först fill, sedan stroke vid behov.

Vad är bitmap CGContext?

Bitmap CGContext — en kontext skapad via CGBitmapContextCreate som ritar till en minnesbuffert istället för skärmen. Används för bakgrundsgenerering av bilder, grafikbearbetning utan visning och skapande av texturer för Metal eller OpenGL.

Hur återställer man alla inställningar i CGContext?

Core Graphics tillhandahåller ingen metod för att återställa alla inställningar. Använd saveGState före ändringar och restoreGState för att återgå till det ursprungliga tillståndet. Alternativt kan man skapa en ny kontext med samma parametrar.

Varför visas inte gradienten inuti formen?

Innan du anropar drawLinearGradient, ställ in klippområdet via clip på den önskade konturen. Utan clip fyller gradienten hela kontexten. Ordningen: addPath → clip → drawLinearGradient — garanterar gradienten inuti formen.

Sammanfattning

  • CGContext — det centrala objektet i Core Graphics för alla 2D-ritoperationer på iOS och macOS.
  • saveGState och restoreGState hanterar kontextens tillståndsstack och förhindrar sidoeffekter.
  • setFillColor och setStrokeColor anger fyllnings- och konturfärger via CGColorRef.
  • addPath, strokePath, fillPath arbetar med godtyckliga CGPath-konturer.
  • clip begränsar ritområdet till den aktuella konturen för masker och rundningar.
  • translateCTM, scaleCTM, rotateCTM transformerar kontextens koordinatsystem.
  • Alla CGContext-operationer utförs på CPU:n — för komplex grafik, använd CGLayer eller Metal.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också