CGContext — a Core Graphics fő objektuma 2D rajzolási parancsok végrehajtásához iOS-ben és macOS-ben. Egy grafikus kontextust képvisel, amely tárolja az aktuális állapotot: kitöltő szín, vonalvastagság, transzformáció, vágóterület és betűtípusok. Minden rajzolási művelet — vonalak, téglalapok, szöveg, képek — a CGContext-en keresztül történik. A Apple Developer Documentation, 2026 szerint a CGContext az Apple ökoszisztémájában a teljes raszter és vektorgrafika alapja.
Főbb pontok
CGContext — egy átlátszatlan típus (opaque type) a Core Graphics keretrendszerből, amely környezetet biztosít 2D megjelenítési parancsok végrehajtásához. Kezeli az állapotok vermét, az aktuális színteret, a koordináta-transzformációt és a vágóterületet. A CGContext az egyetlen objektum, amellyel az összes Quartz 2D rajzolófüggvény kommunikál — minden grafikai művelet rajta keresztül történik.
A CGContext több változatban létezik a céltól függően: bitmap context raszterképekkel való munkához memóriában, PDF context PDF dokumentumok generálásához, window context képernyőn való megjelenítéshez (amelyet a UIView biztosít a draw(_:) módszerben). iOS-ben a fejlesztők leggyakrabban a UIGraphicsGetCurrentContext()-ből a draw(_:) módszerben, vagy a UIGraphicsBeginImageContextWithOptions-ból offline megjelenítéshez kapott kontextussal dolgoznak.
A kontextus minden beállítást az állapotok vermén keresztül alkalmaz — a fejlesztő elmentheti az aktuális állapotot (saveGState), megváltoztathatja a paramétereket és visszaállíthatja az előző állapotot (restoreGState). Ez kritikus fontosságú összetett jelenetek megjelenítésekor, ahol a különböző elemek eltérő színeket, vonalvastagságokat és transzformációkat igényelnek. Az Apple WWDC 2023 szerint az állapotok vermének helyes használata javítja a kód olvashatóságát és megakadályozza a vizuális műtermékeket.
CGContextSaveGState a kontextus aktuális állapotának másolatát helyezi a verembe. Ez az állapot magában foglal minden beállítást: színek, vonalvastagság, transzformáció, árnyékok, vágóterület, betűtípusok. A paraméterek módosítása után a CGContextRestoreGState hívás visszaállítja a kontextust az elmentett állapotba, érvénytelenítve az összes köztes változtatást. A verem legfeljebb 32 állapotot tartalmazhat iOS-ben.
Különböző stílusú elemek csoportjának rajzolásakor (például egy diagram színes szektorai) az állapotok verme kiküszöböli az egyes paraméterek kézi megjegyzésének és visszaállításának szükségességét. saveGState/restoreGState nélkül a fejlesztőnek minden elem után újra be kellene állítania a színt, árnyékot és transzformációt. A verem használata lerövidíti a kódot és megszünteti a visszaállítási hibákat.
Fontos megtartani a mentések és visszaállítások egyensúlyát — minden saveGState-hez tartoznia kell egy restoreGState-nek. Az egyensúly megsértése állapotok szivárgásához vagy idő előtti visszaállításhoz vezet, ami kiszámíthatatlan megjelenítést okoz. Az Xcode statikus analizátora nem ellenőrzi a CGContext verem egyensúlyát, így a helyességért a fejlesztő a felelős. Javasolt a párok do/finally blokkokba csoportosítása.
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 beállítja a kitöltő színt a következő műveletekhez. A szín CGColorRef-ként kerül átadásra, amely információt tartalmaz a színtérről és a színösszetevőkről. CGContextSetStrokeColorWithColor hasonlóan működik a körvonal színéhez. Az Apple a gyakran használt CGColorRef-ek gyorsítótárba helyezését ajánlja a teljesítmény javítása érdekében.
CGContextDrawLinearGradient lineáris gradienst rajzol két pont között megadott színekkel. CGContextDrawRadialGradient radiális gradienst hoz létre, amely az egyik körből a másikba halad. A gradiensekkel való munkához először egy CGGradientRef objektumot kell létrehozni, amely színek és megállási pozíciók tömbjét tartalmazza. A CGContext-ben a gradiensek támogatják az RGB és Grayscale színtereket.
Egy terület kitöltése gradienstől megköveteli a vágóterület előzetes beállítását. Clip nélkül a gradiens a teljes kontextust kitölti, nem csak a kívánt alakzatot. A tipikus minta: út hozzáadása a kontextushoz, a clip meghívása a terület korlátozásához, majd a gradiens megrajzolása. Ezt a mintát minden olyan alkalmazásban használják, amely összetett alakzatok gradiens kitöltését igényli, a gomboktól a hátterekig.
| Függvény | Cél | Színtér |
|---|---|---|
| setFillColor | Kitöltő szín beállítása | Bármely (CGColor-on keresztül) |
| setStrokeColor | Körvonal színének beállítása | Bármely (CGColor-on keresztül) |
| drawLinearGradient | Lineáris gradiens rajzolása | RGB vagy Grayscale |
| drawRadialGradient | Radiális gradiens rajzolása | RGB vagy Grayscale |
CGContextAddPath hozzáad egy korábban létrehozott CGPathRef-et a kontextushoz későbbi megjelenítéshez. Az út hozzáadása után körvonalazható (strokePath), kitölthető (fillPath) vagy mindkét művelet elvégezhető. CGContextBeginPath új útot kezd, törölve az előzőt. A kontextus egyszerre csak egy aktív útot támogat.
CGContextMoveToPoint áthelyezi az út aktuális pontját a megadott koordinátákra. CGContextAddLineToPoint egyenes vonalat rajzol az aktuális ponttól a megadott pontig. CGContextAddCurveToPoint köbös Bézier-görbét ad hozzá, CGContextAddQuadCurveToPoint — kvadratikusat. CGContextClosePath egyenes vonallal zárja az útot az utolsó és az első pont között.
Ellentétben az UIBezierPath-szel, ahol ezeket a módszereket az út objektumán hívják meg, a CGContext-ben közvetlenül a kontextuson hívódnak. Ez a különbség fontos a megközelítés kiválasztásakor: az UIBezierPath kényelmesebb a kontúrok újrafelhasználásához, a CGContext — egyszeri megjelenítéshez minimális többletterheléssel. A CGContext támogatja továbbá a szaggatott vonalakat a CGContextSetLineDash-en, a rugalmas végeket a CGContextSetLineCap-en és a kapcsolódásokat a CGContextSetLineJoin-on keresztül.
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 a rajzolási területet az aktuális útra korlátozza. Az összes következő rajzolási művelet csak ezen a területen belül lesz látható. Ez az alapvető mechanizmus a maszkoláshoz, a sarkok lekerekítéséhez és egyedi elemhatárok létrehozásához. A vágóterület szintén mentésre és visszaállításra kerül a saveGState/restoreGState segítségével.
CGContextTranslateCTM eltolja a kontextus koordináta-rendszerének kezdőpontját. CGContextScaleCTM méretezi az X és Y tengelyeket. CGContextRotateCTM elforgatja a koordináta-rendszert az aktuális kezdőpont körül. A transzformációk összeadódnak — minden következő az aktuális koordináta-rendszerhez viszonyítva kerül alkalmazásra. Az összetett transzformációk (eltolás + forgatás + méretezés) animációhoz és elemek pozicionálásához használatosak.
A vágás és transzformálás együttes használata erőteljes lehetőségeket kínál: lehetőség van összetett maszk rajzolására vágással, majd transzformáció alkalmazására a teljes tartalomra. Tipikus példa — egy kép részének megjelenítése szögben lekerekített élekkel. A műveletek sorrendje fontos: először állítsa be a vágóterületet, majd alkalmazza a transzformációt, azután rajzolja meg a tartalmat. Az Apple azt ajánlja, hogy a CTM (Current Transformation Matrix) változtatásainak számát minimalizáljuk a megjelenítési ciklusban.
override func draw(_ rect: CGRect) {
guard let ctx = UIGraphicsGetCurrentContext() else { return }
ctx.saveGState()
// vágóterület — kör
ctx.addEllipse(in: CGRect(x: 50, y: 50, width: 200, height: 200))
ctx.clip()
// tartalom transzformáció
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()
}
Nézzünk egy teljes példát egy gradiens diagram létrehozására CGContext használatával. A diagram három különböző színű szektort tartalmaz gradiens kitöltéssel és szöveges címkékkel. A kód a saveGState, clip, gradiensek és szövegmegjelenítés kombinációját mutatja be egy kontextusban.
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()
// szöveges címke
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
}
}
}
Ebben a példában a diagram minden szektora a saját saveGState/restoreGState blokkjában rajzolódik. Ez a megközelítés garantálja, hogy az egyik szektor szín- és útbeállításai nem befolyásolják a többit. Az addArc módszer ívet hoz létre a kezdő és végső szög között, a closePath a középponthoz zárja a szektort. A szöveges címke a szektor szögének középvonalára kerül, a pozíció számításához a cos és sin trigonometrikus függvények használatosak.
A gyakori úrajzolás teljesítményének javítása érdekében ajánlott a szögek és pozíciók számításainak gyorsítótárba helyezése egy külön tömbben. A CGContext az összes műveletet a CPU-n hajtja végre, így az összetett, tízesével szektort tartalmazó jelenetek optimalizálást igényelhetnek — például előzetes raszterizálást CGLayer-ben vagy a Metal használatát GPU-gyorsításhoz. A legtöbb 5–10 elemet tartalmazó UI feladat esetén a CGContext teljesítménye elfogadható.
Gyakran ismételt kérdések
Hívja meg a UIGraphicsGetCurrentContext() függvényt a UIView draw(_:) metódusán belül vagy a UIGraphicsBeginImageContextWithOptions blokkon belül. CALayer rétegekhez használja a CALayerDelegate draw(in:) metódusát, amely egy kész kontextust kap.
A fillPath kitölti az aktuális úton belüli területet a setFillColor színével. A strokePath vonalat rajzol az út mentén a setStrokeColor, setLineWidth és setLineCap paraméterekkel. Mindkét művelet egymás után történik: először fill, majd szükség esetén stroke.
A Bitmap CGContext — egy CGBitmapContextCreate segítségével létrehozott kontextus, amely a képernyő helyett egy memóriabufferbe rajzol. Háttérkép-generáláshoz, grafikai feldolgozáshoz megjelenítés nélkül és textúrák létrehozásához Metal vagy OpenGL számára használatos.
A Core Graphics nem biztosít módszert az összes beállítás visszaállítására. Használja a saveGState függvényt a változtatások előtt és a restoreGState függvényt az eredeti állapotba való visszatéréshez. Alternatívaként létrehozhat egy új kontextust ugyanazokkal a paraméterekkel.
A drawLinearGradient meghívása előtt állítsa be a vágóterületet a clip segítségével a kívánt úton. Clip nélkül a gradiens a teljes kontextust kitölti. Sorrend: addPath → clip → drawLinearGradient — garantálja a gradienst az alakzaton belül.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is