CGContext ist das primäre Core Graphics-Objekt zur Ausführung von 2D-Zeichenbefehlen in iOS und macOS. Es repräsentiert einen Grafik-Kontext, der den aktuellen Zustand speichert: Füllfarbe, Linienstärke, Transformation, Beschneidungsbereich und Schriftarten. Alle Zeichenoperationen — Linien, Rechtecke, Text, Bilder — werden über CGContext ausgeführt. Laut Apple Developer Documentation, 2026 ist CGContext die Grundlage aller Raster- und Vektorgrafiken im Apple-Ökosystem.
Wichtige Punkte
CGContext ist ein undurchsichtiger Typ (opaque type) aus dem Core Graphics-Framework, der eine Umgebung zur Ausführung von 2D-Rendering-Befehlen darstellt. Er verwaltet den Zustandsstapel, den aktuellen Farbraum, die Koordinatentransformation und den Beschneidungsbereich. CGContext ist das einzige Objekt, mit dem alle Quartz 2D-Zeichenfunktionen interagieren — jede Grafikoperation läuft durch ihn.
CGContext existiert in mehreren Varianten, je nach Zweck: Bitmap-Kontext für die Arbeit mit Rasterbildern im Speicher, PDF-Kontext zur Erstellung von PDF-Dokumenten, Fenster-Kontext für die Bildschirmdarstellung (bereitgestellt von UIView in draw(_:)). iOS-Entwickler arbeiten am häufigsten mit einem Kontext, der von UIGraphicsGetCurrentContext() innerhalb der draw(_:)-Methode oder von UIGraphicsBeginImageContextWithOptions für das Offline-Rendering bezogen wird.
Der Kontext wendet alle Einstellungen über einen Zustandsstapel an — der Entwickler kann den aktuellen Zustand speichern (saveGState), Parameter ändern und den vorherigen Zustand wiederherstellen (restoreGState). Dies ist bei komplexen Szenen, in denen verschiedene Elemente unterschiedliche Farben, Linienstärken und Transformationen erfordern, von entscheidender Bedeutung. Laut Apple WWDC 2023 verbessert die richtige Verwendung des Zustandsstapels die Lesbarkeit des Codes und verhindert visuelle Artefakte.
CGContextSaveGState legt eine Kopie des aktuellen Kontextzustands auf den Stapel. Dieser Zustand umfasst alle Einstellungen: Farben, Linienstärke, Transformation, Schatten, Beschneidungsbereich, Schriftarten. Nach der Änderung von Parametern bringt der Aufruf von CGContextRestoreGState den Kontext in den gespeicherten Zustand zurück und macht alle zwischenzeitlichen Änderungen rückgängig. Der Stapel kann unter iOS bis zu 32 Zustände aufnehmen.
Beim Zeichnen von Elementgruppen mit unterschiedlichen Stilen (z.B. mehrfarbige Diagrammsektoren) macht der Zustandsstapel das manuelle Merken und Wiederherstellen jedes Parameters überflüssig. Ohne saveGState/restoreGState müsste der Entwickler nach jedem Element Farbe, Schatten und Transformation zurücksetzen. Die Verwendung des Stapels reduziert den Code und verhindert Wiederherstellungsfehler.
Es ist wichtig, ein Gleichgewicht zwischen Speichern und Wiederherstellen zu wahren — jeder saveGState muss einen passenden restoreGState haben. Ein Ungleichgewicht führt zu Zustandslecks oder vorzeitiger Wiederherstellung, was unvorhersehbare Darstellung verursacht. Der statische Analysator von Xcode prüft das Stapelgleichgewicht von CGContext nicht, daher liegt die Korrektheit in der Verantwortung des Entwicklers. Es wird empfohlen, Paare in do/finally-Blöcken zu gruppieren.
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 legt die Füllfarbe für nachfolgende Operationen fest. Die Farbe wird als CGColorRef übergeben, die Informationen über den Farbraum und die Farbkomponenten enthält. CGContextSetStrokeColorWithColor funktioniert analog für die Strichfarbe. Apple empfiehlt, häufig verwendete CGColorRef-Werte zur Leistungssteigerung zwischenzuspeichern.
CGContextDrawLinearGradient zeichnet einen linearen Farbverlauf zwischen zwei Punkten mit angegebenen Farben. CGContextDrawRadialGradient erstellt einen radialen Farbverlauf, der von einem Kreis zum anderen übergeht. Für die Arbeit mit Farbverläufen wird zunächst ein CGGradientRef-Objekt erstellt, das ein Array von Farben und Stoppositionen enthält. Farbverläufe in CGContext unterstützen sowohl RGB- als auch Graustufen-Farbräume.
Das Füllen eines Bereichs mit einem Farbverlauf erfordert das vorherige Festlegen eines Beschneidungsbereichs. Ohne clip füllt der Farbverlauf den gesamten Kontext, nicht nur die gewünschte Form. Das typische Muster: Pfad zum Kontext hinzufügen, clip aufrufen, um den Bereich einzuschränken, dann den Farbverlauf zeichnen. Dieses Muster wird in allen Anwendungen verwendet, die Farbverlaufsfüllungen komplexer Formen benötigen, von Schaltflächen bis zu Hintergründen.
| Funktion | Zweck | Farbraum |
|---|---|---|
| setFillColor | Legt die Füllfarbe fest | Jeder (über CGColor) |
| setStrokeColor | Legt die Strichfarbe fest | Jeder (über CGColor) |
| drawLinearGradient | Zeichnet einen linearen Farbverlauf | RGB oder Graustufen |
| drawRadialGradient | Zeichnet einen radialen Farbverlauf | RGB oder Graustufen |
CGContextAddPath fügt einen zuvor erstellten CGPathRef zum Kontext für die anschließende Darstellung hinzu. Nach dem Hinzufügen eines Pfads kann dieser konturiert (strokePath), gefüllt (fillPath) oder beides werden. CGContextBeginPath startet einen neuen Pfad und löscht den vorherigen. Der Kontext unterstützt jeweils nur einen aktiven Pfad.
CGContextMoveToPoint bewegt den aktuellen Konturpunkt zu den angegebenen Koordinaten. CGContextAddLineToPoint zeichnet eine gerade Linie vom aktuellen Punkt zum angegebenen Punkt. CGContextAddCurveToPoint fügt eine kubische Bézierkurve hinzu, CGContextAddQuadCurveToPoint eine quadratische. CGContextClosePath schließt die Kontur mit einer geraden Linie zwischen dem letzten und ersten Punkt.
Im Gegensatz zu UIBezierPath, bei dem alle diese Methoden auf dem Pfadobjekt aufgerufen werden, werden sie in CGContext direkt auf dem Kontext aufgerufen. Dieser Unterschied ist bei der Wahl des Ansatzes wichtig: UIBezierPath ist für die Wiederverwendung von Pfaden praktischer, CGContext eignet sich besser für einmaliges Zeichnen mit minimalem Overhead. CGContext unterstützt auch gestrichelte Linien über CGContextSetLineDash, flexible Enden über CGContextSetLineCap und Verbindungen über 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 schränkt den Zeichenbereich auf den aktuellen Pfad ein. Alle nachfolgenden Zeichenoperationen sind nur innerhalb dieses Bereichs sichtbar. Dies ist der grundlegende Mechanismus zum Maskieren, Abrunden von Ecken und Erstellen benutzerdefinierter Elementgrenzen. Der Beschneidungsbereich wird auch über saveGState/restoreGState gespeichert und wiederhergestellt.
CGContextTranslateCTM verschiebt den Ursprung des Koordinatensystems des Kontexts. CGContextScaleCTM skaliert die X- und Y-Achsen. CGContextRotateCTM dreht das Koordinatensystem um den aktuellen Ursprung. Transformationen akkumulieren — jede nachfolgende wird relativ zum aktuellen Koordinatensystem angewendet. Zusammengesetzte Transformationen (Verschiebung + Drehung + Skalierung) werden für Animation und Elementpositionierung verwendet.
Die Kombination von Beschneidung und Transformation bietet leistungsstarke Möglichkeiten: Eine komplexe Maske kann durch Beschneidung gezeichnet werden, dann kann eine Transformation auf den gesamten Inhalt angewendet werden. Ein typisches Beispiel ist die Darstellung eines Bildteils in einem Winkel mit abgerundeten Ecken. Die Reihenfolge der Operationen ist wichtig: Zuerst den Beschneidungsbereich festlegen, dann die Transformation anwenden, dann den Inhalt zeichnen. Apple empfiehlt, Änderungen der CTM (Current Transformation Matrix) im Zeichen-Loop zu minimieren.
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()
}
Betrachten wir ein vollständiges Beispiel zur Erstellung eines Farbverlaufsdiagramms mit CGContext. Das Diagramm umfasst drei Sektoren in verschiedenen Farben mit Farbverlaufsfüllungen und Textbeschriftungen. Der Code demonstriert die Kombination von saveGState, clip, Farbverläufen und Textdarstellung in einem einzigen 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()
// 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
}
}
}
In diesem Beispiel wird jeder Diagrammsektor in einem eigenen saveGState/restoreGState-Block gezeichnet. Dieser Ansatz stellt sicher, dass die Farb- und Pfadeinstellungen eines Sektors andere nicht beeinflussen. Die addArc-Methode erzeugt einen Bogen vom Start- zum Endwinkel, und closePath schließt den Sektor zur Mitte hin. Der Beschriftungstext wird am mittleren Winkel des Sektors platziert, wobei die trigonometrischen Funktionen cos und sin zur Positionsberechnung verwendet werden.
Zur Leistungsverbesserung bei häufigen Neuzeichnungen wird empfohlen, Winkel- und Positionsberechnungen in einem separaten Array zwischenzuspeichern. CGContext führt alle Operationen auf der CPU aus, daher können komplexe Szenen mit Dutzenden von Sektoren Optimierung erfordern — zum Beispiel Vorab-Rendering in CGLayer oder die Verwendung von Metal für GPU-Beschleunigung. Für die meisten UI-Aufgaben mit 5–10 Elementen bleibt die Leistung von CGContext akzeptabel.
Häufig gestellte Fragen
Rufen Sie UIGraphicsGetCurrentContext() innerhalb der draw(_:)-Methode von UIView oder innerhalb eines UIGraphicsBeginImageContextWithOptions-Blocks auf. Für CALayer-Ebenen verwenden Sie die draw(in:)-Methode von CALayerDelegate, die einen fertigen Kontext empfängt.
fillPath füllt das Innere des aktuellen Pfads mit der Farbe von setFillColor. strokePath zeichnet eine Linie entlang des Pfads mit den Parametern von setStrokeColor, setLineWidth und setLineCap. Beide Operationen werden nacheinander ausgeführt: zuerst Füllung, dann bei Bedarf Strich.
Bitmap CGContext ist ein über CGBitmapContextCreate erstellter Kontext, der in einen Speicherpuffer statt auf den Bildschirm zeichnet. Er wird für die Hintergrundbilderzeugung, Grafikverarbeitung ohne Anzeige und die Erstellung von Texturen für Metal oder OpenGL verwendet.
Core Graphics bietet keine Methode zum Zurücksetzen aller Einstellungen. Verwenden Sie saveGState vor Änderungen und restoreGState zur Rückkehr zum ursprünglichen Zustand. Alternativ können Sie einen neuen Kontext mit denselben Parametern erstellen.
Vor dem Aufruf von drawLinearGradient legen Sie den Beschneidungsbereich über clip auf dem gewünschten Pfad fest. Ohne clip füllt der Farbverlauf den gesamten Kontext. Reihenfolge: addPath → clip → drawLinearGradient — garantiert den Farbverlauf innerhalb der Form.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch