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 — 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.
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.
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.
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()
}
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.
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.
| Funktion | Syfte | Färgrymd |
|---|---|---|
| setFillColor | Anger fyllningsfärg | Valfritt (via CGColor) |
| setStrokeColor | Anger konturfärg | Valfritt (via CGColor) |
| drawLinearGradient | Ritar linjär gradient | RGB eller Grayscale |
| drawRadialGradient | Ritar radiell gradient | RGB eller Grayscale |
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.
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.
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()
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.
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.
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()
}
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.
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
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.
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.
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.
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.
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
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.
Läs också