CGContext v iOS — co to je, metody a jak spravovat kontext kreslení

Autor: IT Sectr Publikováno: 2026-07-21 Doba čtení: 9 min

CGContext — hlavní objekt Core Graphics pro provádění 2D příkazů kreslení v iOS a macOS. Představuje grafický kontext, který uchovává aktuální stav: barvu výplně, tloušťku čáry, transformaci, oblast oříznutí a fonty. Všechny operace kreslení — čáry, obdélníky, text, obrázky — se provádějí přes CGContext. Podle Apple Developer Documentation, 2026 je CGContext základem veškeré rastrové a vektorové grafiky v ekosystému Apple.

Hlavní body

  • CGContext — grafický kontext, přes který se provádějí všechny 2D příkazy Core Graphics.
  • setStrokeColor a setFillColor spravují barvu čar a výplní v kontextu.
  • addPath a drawPath umožňují kreslit libovolné CGPath obrysy.
  • clip(to:) nastavuje oblast oříznutí pro omezení kreslení na určitou zónu.
  • saveGState a restoreGState ukládají a obnovují zásobník stavů kontextu.

Co je CGContext?

CGContext — neprůhledný typ (opaque type) z frameworku Core Graphics, představující prostředí pro provádění 2D vykreslovacích příkazů. Spravuje zásobník stavů, aktuální barevný prostor, transformaci souřadnic a oblast oříznutí. CGContext je jediný objekt, se kterým interagují všechny kreslicí funkce Quartz 2D — přes něj probíhají veškeré grafické operace.

CGContext existuje v několika variantách podle účelu: bitmap context pro práci s rastrovými obrázky v paměti, PDF context pro generování PDF dokumentů, window context pro vykreslování na obrazovku (poskytovaný UIView v draw(_:)). V iOS vývojáři nejčastěji pracují s kontextem získaným z UIGraphicsGetCurrentContext() uvnitř metody draw(_:) nebo z UIGraphicsBeginImageContextWithOptions pro offline renderování.

Kontext aplikuje všechna nastavení přes zásobník stavů — vývojář může uložit aktuální stav (saveGState), změnit parametry a obnovit předchozí (restoreGState). To je kriticky důležité při kreslení složitých scén, kde různé prvky vyžadují různé barvy, tloušťky čar a transformace. Podle Apple WWDC 2023 správné používání zásobníku stavů zvyšuje čitelnost kódu a předchází vizuálním artefaktům.

Správa stavu: saveGState a restoreGState

CGContextSaveGState vloží kopii aktuálního stavu kontextu do zásobníku. Tento stav zahrnuje všechna nastavení: barvy, tloušťku čáry, transformaci, stíny, oblast oříznutí, fonty. Po úpravě parametrů volání CGContextRestoreGState vrátí kontext do uloženého stavu a zruší všechny mezilehlé změny. Zásobník může v iOS obsahovat až 32 stavů.

Praktické použití zásobníku

Při kreslení skupiny prvků s různými styly (např. různobarevné sektory grafu) zásobník stavů odstraňuje nutnost ručně si pamatovat a obnovovat každý parametr. Bez saveGState/restoreGState by vývojář musel po každém prvku znovu nastavovat barvu, stín a transformaci. Použití zásobníku zkracuje kód a eliminuje chyby obnovy.

Je důležité dodržovat rovnováhu ukládání a obnovování — každý saveGState musí mít párový restoreGState. Porušení rovnováhy vede k úniku stavů nebo předčasnému obnovení, což způsobuje nepředvídatelné zobrazení. Statický analyzátor Xcode nekontroluje rovnováhu zásobníku CGContext, proto odpovědnost za správnost leží na vývojáři. Doporučuje se seskupovat páry do do/finally bloků.

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

Barvy a výplně

CGContextSetFillColorWithColor nastavuje barvu výplně pro následující operace. Barva se předává jako CGColorRef, který obsahuje informace o barevném prostoru a složkách barvy. CGContextSetStrokeColorWithColor funguje analogicky pro barvu obrysu. Apple doporučuje ukládat do mezipaměti často používané CGColorRef pro zvýšení výkonu.

Přechody v CGContext

CGContextDrawLinearGradient kreslí lineární přechod mezi dvěma body s určenými barvami. CGContextDrawRadialGradient vytváří radiální přechod přecházející z jednoho kruhu do druhého. Pro práci s přechody se nejprve vytvoří objekt CGGradientRef obsahující pole barev a pozic zastávek. Přechody v CGContext podporují jak RGB, tak Grayscale barevné prostory.

Vyplnění oblasti přechodem vyžaduje předchozí nastavení oblasti oříznutí. Bez clip přechod vyplní celý kontext, nejen požadovaný tvar. Typický vzor: přidat cestu do kontextu, zavolat clip pro omezení oblasti, pak nakreslit přechod. Tento vzor se používá ve všech aplikacích, kde je vyžadováno přechodové vyplnění složitých tvarů, od tlačítek po pozadí.

FunkceÚčelBarevný prostor
setFillColorNastavuje barvu výplněLibovolný (přes CGColor)
setStrokeColorNastavuje barvu obrysuLibovolný (přes CGColor)
drawLinearGradientKreslí lineární přechodRGB nebo Grayscale
drawRadialGradientKreslí radiální přechodRGB nebo Grayscale

Kreslení obrysů a čar

CGContextAddPath přidá dříve vytvořený CGPathRef do kontextu pro následné vykreslení. Po přidání cesty ji lze obkreslit (strokePath), vyplnit (fillPath) nebo provést obě operace. CGContextBeginPath zahájí novou cestu a vyčistí předchozí. Kontext podporuje v každém okamžiku pouze jednu aktivní cestu.

Přímé čáry a křivky po bodech

CGContextMoveToPoint přesune aktuální bod cesty do určených souřadnic. CGContextAddLineToPoint nakreslí přímku z aktuálního bodu do zadaného. CGContextAddCurveToPoint přidá kubickou Bézierovu křivku, CGContextAddQuadCurveToPoint kvadratickou. CGContextClosePath uzavře cestu přímkou mezi posledním a prvním bodem.

Na rozdíl od UIBezierPath, kde jsou všechny tyto metody volány na objektu cesty, v CGContext se volají přímo na kontextu. Tento rozdíl je důležitý při výběru přístupu: UIBezierPath je vhodnější pro opakované použití obrysů, CGContext pro jednorázové kreslení s minimální režií. CGContext také podporuje čárkované čáry přes CGContextSetLineDash, flexibilní zakončení přes CGContextSetLineCap a spoje přes 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()

Oblast oříznutí a transformace

CGContextClip omezuje oblast kreslení na aktuální obrys. Všechny následující operace kreslení budou viditelné pouze uvnitř této oblasti. To je základní mechanismus pro maskování, zakulacování rohů a vytváření nestandardních okrajů prvků. Oblast oříznutí se také ukládá a obnovuje přes saveGState/restoreGState.

Transformace souřadnic

CGContextTranslateCTM posouvá počátek souřadnic kontextu. CGContextScaleCTM škáluje osy X a Y. CGContextRotateCTM otáčí souřadnicový systém kolem aktuálního počátku. Transformace se kumulují — každá následující se aplikuje relativně k aktuálnímu souřadnicovému systému. Složené transformace (posun + rotace + měřítko) se používají pro animace a pozicování prvků.

Kombinované použití oříznutí a transformace poskytuje mocné možnosti: lze nakreslit složitou masku přes oříznutí a poté aplikovat transformaci na celý obsah. Typický příklad — zobrazení části obrázku pod úhlem se zaoblenými rohy. Pořadí operací je důležité: nejprve nastavit oblast oříznutí, pak aplikovat transformaci, poté kreslit obsah. Apple doporučuje minimalizovat počet změn CTM (Current Transformation Matrix) ve vykreslovací smyčce.

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

    // oblast oříznutí - kruh
    ctx.addEllipse(in: CGRect(x: 50, y: 50, width: 200, height: 200))
    ctx.clip()

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

Příklad kreslení v CGContext

Podívejme se na úplný příklad vytvoření přechodového grafu pomocí CGContext. Graf zahrnuje tři sektory různých barev s přechodovou výplní a textovými popisky. Kód demonstruje kombinaci saveGState, clip, přechodů a vykreslování textu v jednom kontextu.

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

            // textový popisek
            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
        }
    }
}

V tomto příkladu je každý sektor grafu kreslen ve vlastním saveGState/restoreGState bloku. Takový přístup zaručuje, že nastavení barvy a cesty pro jeden sektor neovlivní ostatní. Metoda addArc vytvoří oblouk od počátečního do koncového úhlu, closePath uzavře sektor ke středu. Textový popisek je umístěn na střední čáře úhlu sektoru s použitím trigonometrických funkcí cos a sin pro výpočet pozice.

Pro zvýšení výkonu při častém překreslování se doporučuje ukládat výpočet úhlů a pozic do mezipaměti v samostatném poli. CGContext provádí všechny operace na CPU, proto složité scény s desítkami sektorů mohou vyžadovat optimalizaci — například předběžnou rasterizaci v CGLayer nebo použití Metal pro akceleraci GPU. Pro většinu UI úloh s 5–10 prvky zůstává výkon CGContext přijatelný.

Často kladené otázky

Jak získat aktuální CGContext v iOS?

Zavolejte UIGraphicsGetCurrentContext() uvnitř metody draw(_:) UIView nebo uvnitř bloku UIGraphicsBeginImageContextWithOptions. Pro vrstvy CALayer použijte draw(in:) delegáta CALayerDelegate, který obdrží hotový kontext.

Jaký je rozdíl mezi fillPath a strokePath?

fillPath vyplní vnitřní oblast aktuálního obrysu barvou z setFillColor. strokePath kreslí čáru podél obrysu s parametry setStrokeColor, setLineWidth a setLineCap. Obě operace se provádějí postupně: nejprve fill, poté stroke v případě potřeby.

Co je bitmap CGContext?

Bitmap CGContext — kontext vytvořený přes CGBitmapContextCreate, který kreslí do paměťového bufferu místo na obrazovku. Používá se pro generování obrázků na pozadí, zpracování grafiky bez zobrazení a vytváření textur pro Metal nebo OpenGL.

Jak resetovat všechna nastavení CGContext?

Core Graphics neposkytuje metodu pro resetování všech nastavení. Použijte saveGState před změnami a restoreGState pro návrat do původního stavu. Alternativně můžete vytvořit nový kontext se stejnými parametry.

Proč se přechod nezobrazuje uvnitř tvaru?

Před voláním drawLinearGradient nastavte oblast oříznutí přes clip na požadovaný obrys. Bez clip přechod vyplní celý kontext. Pořadí: addPath → clip → drawLinearGradient — zaručuje přechod uvnitř tvaru.

Shrnutí

  • CGContext — centrální objekt Core Graphics pro všechny 2D operace kreslení na iOS a macOS.
  • saveGState a restoreGState spravují zásobník stavů kontextu a zabraňují vedlejším účinkům.
  • setFillColor a setStrokeColor nastavují barvy výplně a obrysu přes CGColorRef.
  • addPath, strokePath, fillPath pracují s libovolnými obrysy CGPath.
  • clip omezuje oblast kreslení na aktuální obrys pro masky a zakulacení.
  • translateCTM, scaleCTM, rotateCTM transformují souřadnicový systém kontextu.
  • Všechny operace CGContext se provádějí na CPU — pro složitou grafiku použijte CGLayer nebo Metal.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také