CGContext у iOS-у — шта је, методе и како управљати контекстом цртања

Аутор: IT Sectr Објављено: 2026-07-21 Време читања: 9 мин

CGContext — основни објекат Core Graphics-а за извршавање 2D наредби цртања у iOS-у и macOS-у. Он представља графички контекст који чува тренутно стање: боју испуне, дебљину линије, трансформацију, област одсецања и фонтове. Све операције цртања — линије, правоугаоници, текст, слике — извршавају се кроз CGContext. Према Apple Developer Documentation, 2026, CGContext је темељ целокупне растерске и векторске графике у екосистему Apple-а.

Главно

  • CGContext — графички контекст кроз који се извршавају све 2D наредбе Core Graphics-а.
  • setStrokeColor и setFillColor управљају бојом линија и испуна у контексту.
  • addPath и drawPath омогућавају цртање произвољних CGPath контура.
  • clip(to:) поставља област одсецања за ограничавање цртања на одређену зону.
  • saveGState и restoreGState чувају и враћају стек стања контекста.

Шта је CGContext?

CGContext — непрозиран тип (opaque type) из оквира Core Graphics-а који представља окружење за извршавање 2D наредби рендеровања. Он управља стеком стања, тренутним простором боја, трансформацијом координата и облашчу одсецања. CGContext је једини објекат са којим интерагују све функције цртања Quartz 2D-а — кроз њега пролазе све графичке операције.

CGContext постоји у више варијанати у зависности од намене: bitmap context за рад са растерским сликама у меморији, PDF context за генерацију PDF докумената, window context за исцртавање на екрану (који обезбеђује UIView у draw(_:)). У iOS-у, програмери најчешће раде са контекстом добијеним из UIGraphicsGetCurrentContext() унутар методе draw(_:) или из UIGraphicsBeginImageContextWithOptions за офлајн рендеровање.

Контекст примењује све поставке кроз стек стања — програмер може да сачува тренутно стање (saveGState), промијени параметре и врати претходно (restoreGState). Ово је критично приликом рендеровања сложених сцена где различити елементи захтевају различите боје, дебљине линија и трансформације. Према Apple WWDC 2023, правилно коришћење стека стања побољшава читљивост кода и спречава визуелне артефакте.

Управљање стањем: saveGState и restoreGState

CGContextSaveGState ставља копију тренутног стања контекста у стек. Ово стање укључује све поставке: боје, дебљину линије, трансформацију, сенке, област одсецања, фонтове. Након измене параметара, позив CGContextRestoreGState враћа контекст у сачувано стање, поништавајући све међуизмене. Стек може да садржи до 32 стања на iOS-у.

Практична примена стека

Приликом цртања групе елемената са различитим стиловима (на пример, разнобојни сектори дијаграма) стек стања отклања потребу за ручним памћењем и враћањем сваког параметра. Без saveGState/restoreGState, програмер би морао поново да постави боју, сенку и трансформацију након сваког елемента. Коришћење стека скраћује код и елиминише грешке враћања.

Важно је одржати равнотежу чувања и враћања — сваки saveGState мора да има парни restoreGState. Нарушавање равнотеже доводи до цурења стања или превременог враћања, што изазива непредвидиво приказивање. Xcode статички анализатор не проверава равнотежу стека CGContext-а, па је одговорност за исправност на програмеру. Препоручује се груписање парова у do/finally блокове.

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

Боје и испуне

CGContextSetFillColorWithColor поставља боју испуне за наредне операције. Боја се преноси као CGColorRef, који садржи информације о простору боја и компонентама боје. CGContextSetStrokeColorWithColor ради аналогно за боју обриса. Apple препоручује кеширање често коришћених CGColorRef-а за побољшање перформанси.

Градијенти у CGContext-у

CGContextDrawLinearGradient црта линеарни градијент између двију тачака са наведеним бојама. CGContextDrawRadialGradient ствара радијални градијент који прелази са једног круга на други. За рад са градијентима, прво се ствара CGGradientRef објекат који садржи низ боја и позиција заустављања. Градијенти у CGContext-у подржавају и RGB и Grayscale просторе боја.

Испуњавање области градијентом захтева претходно постављање области одсецања. Без clip-а, градијент ће испунити цео контекст, а не само потребан облик. Типичан образац: додати путању у контекст, позвати clip за ограничавање области, затим нацртати градијент. Овај образац се користи у свим апликацијама које захтевају градијентно испуњавање сложених облика, од дугмића до позадина.

ФункцијаНаменаПростор боја
setFillColorПоставља боју испунеБило који (кроз CGColor)
setStrokeColorПоставља боју обрисаБило који (кроз CGColor)
drawLinearGradientЦрта линеарни градијентRGB или Grayscale
drawRadialGradientЦрта радијални градијентRGB или Grayscale

Цртање контура и линија

CGContextAddPath додаје претходно креирани CGPathRef у контекст за касније рендеровање. Након додавања путање, она се може обрисати (strokePath), испунити (fillPath) или и једно и друго. CGContextBeginPath започиње нову путању, бришући претходну. Контекст подржава само једну активну путању у сваком тренутку.

Праве линије и криве по тачкама

CGContextMoveToPoint помјера тренутну тачку путање на наведене координате. CGContextAddLineToPoint црта праву линију од тренутне тачке до наведене. CGContextAddCurveToPoint додаје кубну Безијерову криву, CGContextAddQuadCurveToPoint — квадратну. CGContextClosePath затвара путању правом линијом између последње и прве тачке.

За разлику од UIBezierPath-а, где се све ове методе позивају на објекту путање, у CGContext-у оне се позивају директно на контексту. Ова разлика је важна при одабиру приступа: UIBezierPath је погоднији за поновну употребу контура, CGContext — за једнократно рендеровање са минималним оптерећењем. CGContext такође подржава испрекидане линије кроз CGContextSetLineDash, флексибилне крајеве кроз CGContextSetLineCap и спојеве кроз 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()

Област одсецања и трансформације

CGContextClip ограничава област цртања на тренутну путању. Све наредне операције цртања биће видљиве само унутар ове области. Ово је основни механизам за маскирање, заокругљивање углова и креирање нестандардних ивица елемената. Област одсецања се такође чува и враћа кроз saveGState/restoreGState.

Трансформација координата

CGContextTranslateCTM помјера почетак координата контекста. CGContextScaleCTM размерава осе X и Y. CGContextRotateCTM ротира координатни систем око тренутног почетка. Трансформације се акумулирају — свака следећа се примењује у односу на тренутни координатни систем. Сложене трансформације (помијерање + ротација + размеравање) користе се за анимацију и позиционирање елемената.

Заједничко коришћење одсецања и трансформације пружа моћне могућности: може се нацртати сложена маска кроз одсецање, а затим применити трансформацију на цеокупни садржај. Типичан примјер — приказивање дела слике под углом са заокругљеним ивицама. Редослед операција је важан: прво поставити област одсецања, затим применити трансформацију, затим цртати садржај. Apple препоручује да се број измена CTM (Current Transformation Matrix) у петљи рендеровања сведе на минимум.

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

    // област одсецања — круг
    ctx.addEllipse(in: CGRect(x: 50, y: 50, width: 200, height: 200))
    ctx.clip()

    // трансформација садржаја
    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()
}

Пример цртања у CGContext-у

Размотримо потпуни примјер креирања градијентног дијаграма коришћењем CGContext-а. Дијаграм укључује три сектора различитих боја са градијентним испунавањем и текстуалним натписима. Код демонстрира комбинацију saveGState, clip, градијената и рендеровања текста у једном контексту.

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

            // текстуална етикета
            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
        }
    }
}

У овом примјеру, сваки сектор дијаграма црта се у сопственом saveGState/restoreGState блоку. Овакав приступ гарантује да поставке боје и путање за један сектор не утичу на друге. Метода addArc ствара лук од почетног до крањег угла, closePath затвара сектор ка центру. Текстуални натпис се поставља на средњој линији угла сектора коришћећем тригонометријских функција cos и sin за израчунавање положаја.

За повећање перформанси при честом прецртавању, препоручује се кеширање израчунавања углова и положаја у засебном низу. CGContext извршава све операције на CPU-у, па сложене сцене са десетинама сектора могу захтевати оптимизацију — на примјер, претходну растеризацију у CGLayer или коришћење Metal-а за GPU убрзање. За већину UI задатака са 5–10 елемената, перформансе CGContext-а је прихватљива.

Често постављана питања

Како добити тренутни CGContext у iOS-у?

Позовите UIGraphicsGetCurrentContext() унутар методе draw(_:) UIView-а или унутар UIGraphicsBeginImageContextWithOptions блока. За CALayer слојеве, користите draw(in:) делегата CALayerDelegate, који добија готов контекст.

Која је разлика између fillPath и strokePath?

fillPath испуњава унутрашњу област тренутне путање бојом из setFillColor. strokePath црта линију дуж путање са параметрима setStrokeColor, setLineWidth и setLineCap. Обе операције се извршавају секвенцијално: прво fill, затим stroke ако је потребно.

Шта је bitmap CGContext?

Bitmap CGContext — контекст креиран кроз CGBitmapContextCreate који црта у меморијски буфер уместо на екран. Користи се за генерацију слика у позадини, обраду графике без приказивања и креирање текстура за Metal или OpenGL.

Како ресетовати све поставке CGContext-а?

Core Graphics не пружа методу за ресетовање свих поставки. Користите saveGState пре измена и restoreGState за повратак у првобитно стање. Алтернативно, можете креирати нови контекст са истим параметрима.

Зашто се градијент не приказује унутар облика?

Пре позива drawLinearGradient, поставите област одсецања кроз clip на жељену путању. Без clip-а, градијент испуњава цео контекст. Редослед: addPath → clip → drawLinearGradient — гарантује градијент унутар облика.

Закључак

  • CGContext — централни објекат Core Graphics-а за све 2D операције цртања на iOS-у и macOS-у.
  • saveGState и restoreGState управљају стеком стања контекста, спречавајући споредне ефекте.
  • setFillColor и setStrokeColor постављају боје испуне и обриса кроз CGColorRef.
  • addPath, strokePath, fillPath раде са произвољним CGPath контурима.
  • clip ограничава област цртања на тренутну путању за маске и заокругљења.
  • translateCTM, scaleCTM, rotateCTM трансформишу координатни систем контекста.
  • Све CGContext операције се извршавају на CPU-у — за сложену графику користите CGLayer или Metal.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође