CGContext sa iOS — ano ito, mga pamamaraan at kung paano pamahalaan ang konteksto ng pagguhit

May-akda: IT Sectr Nai-publish: 2026-07-21 Oras ng pagbabasa: 9 min

CGContext — ang pangunahing bagay ng Core Graphics para sa pagsasagawa ng mga 2D na utos ng pagguhit sa iOS at macOS. Kinakatawan nito ang isang grapikong konteksto na nag-iimbak ng kasalukuyang estado: kulay ng fill, kapal ng linya, transformasyon, lugar ng pag-clip, at mga font. Lahat ng operasyon ng pagguhit — mga linya, parihaba, teksto, larawan — ay isinasagawa sa pamamagitan ng CGContext. Ayon sa Apple Developer Documentation, 2026, ang CGContext ay ang pundasyon ng lahat ng raster at vector graphics sa ecosystem ng Apple.

Mga Pangunahing Punto

  • CGContext — ang grapikong konteksto kung saan isinasagawa ang lahat ng 2D Core Graphics na utos.
  • setStrokeColor at setFillColor namamahala sa kulay ng mga linya at fill sa konteksto.
  • addPath at drawPath nagbibigay-daan sa pagguhit ng mga arbitraryong CGPath contour.
  • clip(to:) nagtatakda ng lugar ng pag-clip upang limitahan ang pagguhit sa isang tiyak na sona.
  • saveGState at restoreGState nagse-save at nagpapanumbalik ng stack ng mga estado ng konteksto.

Ano ang CGContext?

CGContext — isang opaque type mula sa Core Graphics framework na kumakatawan sa isang kapaligiran para sa pagsasagawa ng mga 2D rendering na utos. Namamahala ito sa stack ng estado, kasalukuyang espasyo ng kulay, transformasyon ng coordinate, at lugar ng pag-clip. Ang CGContext ay ang tanging bagay na nakikipag-ugnayan sa lahat ng function ng pagguhit ng Quartz 2D — lahat ng grapikong operasyon ay dumadaan dito.

Ang CGContext ay may ilang variant depende sa layunin: bitmap context para sa pagtatrabaho sa mga raster na larawan sa memorya, PDF context para sa pagbuo ng mga PDF document, window context para sa rendering sa screen (ibinibigay ng UIView sa draw(_:)). Sa iOS, ang mga developer ay madalas na nagtatrabaho sa kontekstong nakuha mula sa UIGraphicsGetCurrentContext() sa loob ng draw(_:) na pamamaraan o mula sa UIGraphicsBeginImageContextWithOptions para sa offline rendering.

Inilalapat ng konteksto ang lahat ng setting sa pamamagitan ng stack ng estado — ang developer ay maaaring mag-save ng kasalukuyang estado (saveGState), baguhin ang mga parameter, at ibalik ang nakaraang estado (restoreGState). Ito ay kritikal sa pag-render ng mga kumplikadong eksena kung saan ang iba’t ibang elemento ay nangangailangan ng iba’t ibang kulay, kapal ng linya, at transformasyon. Ayon sa Apple WWDC 2023, ang tamang paggamit ng stack ng estado ay nagpapabuti sa pagiging nababasa ng code at pumipigil sa mga visual artifact.

Pamamahala ng Estado: saveGState at restoreGState

CGContextSaveGState ay naglalagay ng kopya ng kasalukuyang estado ng konteksto sa stack. Ang estadong ito ay sumasaklaw sa lahat ng setting: mga kulay, kapal ng linya, transformasyon, anino, lugar ng pag-clip, mga font. Pagkatapos baguhin ang mga parameter, ang tawag na CGContextRestoreGState ay nagbabalik ng konteksto sa naka-save na estado, na binabawi ang lahat ng pansamantalang pagbabago. Ang stack ay maaaring maglaman ng hanggang 32 estado sa iOS.

Praktikal na Aplikasyon ng Stack

Sa pagguhit ng isang grupo ng mga elemento na may iba’t ibang estilo (halimbawa, ang mga makukulay na sektor ng isang diagram), inaalis ng stack ng estado ang pangangailangan na manu-manong tandaan at ibalik ang bawat parameter. Kung walang saveGState/restoreGState, ang developer ay kailangang muling itakda ang kulay, anino, at transformasyon pagkatapos ng bawat elemento. Ang paggamit ng stack ay nagpapaikli sa code at nag-aalis ng mga error sa pagpapanumbalik.

Mahalagang mapanatili ang balanse ng pag-save at pagpapanumbalik — bawat saveGState ay dapat may katumbas na restoreGState. Ang paglabag sa balanse ay humahantong sa pagtagas ng estado o maagang pagpapanumbalik, na nagdudulot ng hindi inaasahang pagpapakita. Ang static analyzer ng Xcode ay hindi nagsusuri ng balanse ng CGContext stack, kaya ang responsibilidad para sa kawastuhan ay nasa developer. Inirerekomenda ang pagpapangkat ng mga pares sa mga bloke ng 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()
}

Mga Kulay at Fill

CGContextSetFillColorWithColor ay nagtatakda ng kulay ng fill para sa mga susunod na operasyon. Ang kulay ay ipinapasa bilang CGColorRef, na naglalaman ng impormasyon tungkol sa espasyo ng kulay at mga bahagi ng kulay. CGContextSetStrokeColorWithColor ay gumagana nang katulad para sa kulay ng stroke. Inirerekomenda ng Apple ang pag-cache ng mga madalas gamitin na CGColorRef para sa pagpapabuti ng pagganap.

Mga Gradient sa CGContext

CGContextDrawLinearGradient ay gumuhit ng isang linear gradient sa pagitan ng dalawang punto na may tinukoy na mga kulay. CGContextDrawRadialGradient ay lumilikha ng isang radial gradient na lumilipat mula sa isang bilog patungo sa isa pa. Upang magtrabaho sa mga gradient, unang nilikha ang isang CGGradientRef object na naglalaman ng isang array ng mga kulay at posisyon ng paghinto. Ang mga gradient sa CGContext ay sumusuporta sa parehong RGB at Grayscale color space.

Ang pagpuno ng isang lugar na may gradient ay nangangailangan ng paunang pagtatakda ng lugar ng pag-clip. Kung walang clip, pupunuin ng gradient ang buong konteksto, hindi lamang ang nais na hugis. Ang tipikal na pattern: magdagdag ng isang path sa konteksto, tawagan ang clip upang limitahan ang lugar, pagkatapos ay iguhit ang gradient. Ang pattern na ito ay ginagamit sa lahat ng application na nangangailangan ng gradient fill ng mga kumplikadong hugis, mula sa mga button hanggang sa mga background.

FunctionLayuninEspasyo ng Kulay
setFillColorNagtatakda ng kulay ng fillKahit ano (sa pamamagitan ng CGColor)
setStrokeColorNagtatakda ng kulay ng strokeKahit ano (sa pamamagitan ng CGColor)
drawLinearGradientGumuhit ng linear gradientRGB o Grayscale
drawRadialGradientGumuhit ng radial gradientRGB o Grayscale

Pagguhit ng mga Contour at Linya

CGContextAddPath ay nagdaragdag ng isang naunang ginawang CGPathRef sa konteksto para sa susunod na rendering. Pagkatapos idagdag ang path, maaari itong i-stroke (strokePath), punan (fillPath), o pareho. CGContextBeginPath ay nagsisimula ng isang bagong path, na binubura ang nauna. Ang konteksto ay sumusuporta lamang sa isang aktibong path sa bawat pagkakataon.

Mga Tuwid na Linya at Kurba Batay sa Puntos

CGContextMoveToPoint ay naglilipat ng kasalukuyang punto ng path sa tinukoy na mga coordinate. CGContextAddLineToPoint ay gumuhit ng isang tuwid na linya mula sa kasalukuyang punto patungo sa ibinigay na punto. CGContextAddCurveToPoint ay nagdaragdag ng isang cubic Bézier curve, CGContextAddQuadCurveToPoint — isang quadratic. CGContextClosePath ay nagsasara ng path na may isang tuwid na linya sa pagitan ng huli at unang punto.

Hindi tulad ng UIBezierPath, kung saan ang lahat ng mga pamamaraang ito ay tinatawag sa object ng path, sa CGContext ang mga ito ay direktang tinatawag sa konteksto. Ang pagkakaibang ito ay mahalaga sa pagpili ng approach: ang UIBezierPath ay mas maginhawa para sa muling paggamit ng mga contour, ang CGContext — para sa one-time rendering na may minimal na overhead. Sinusuportahan din ng CGContext ang mga dashed line sa pamamagitan ng CGContextSetLineDash, flexible na mga dulo sa pamamagitan ng CGContextSetLineCap, at mga koneksyon sa pamamagitan ng 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()

Lugar ng Pag-clip at mga Transformasyon

CGContextClip ay naglilimita sa lugar ng pagguhit sa kasalukuyang path. Lahat ng susunod na operasyon ng pagguhit ay makikita lamang sa loob ng lugar na ito. Ito ang pangunahing mekanismo para sa masking, pag-round ng mga sulok, at paglikha ng mga custom na hangganan ng elemento. Ang lugar ng pag-clip ay nai-save at naibabalik din sa pamamagitan ng saveGState/restoreGState.

Transformasyon ng Coordinate

CGContextTranslateCTM ay naglilipat ng pinagmulan ng coordinate ng konteksto. CGContextScaleCTM ay nag-scale ng X at Y axes. CGContextRotateCTM ay umiikot ng coordinate system sa paligid ng kasalukuyang pinagmulan. Ang mga transformasyon ay naipon — bawat kasunod ay inilalapat kaugnay sa kasalukuyang coordinate system. Ang mga komposisyong transformasyon (paglipat + pag-ikot + pag-scale) ay ginagamit para sa animation at pagpoposisyon ng mga elemento.

Ang pinagsamang paggamit ng pag-clip at transformasyon ay nagbibigay ng makapangyarihang mga kakayahan: maaaring gumuhit ng isang kumplikadong maskara sa pamamagitan ng pag-clip, pagkatapos ay maglapat ng transformasyon sa buong nilalaman. Isang tipikal na halimbawa — pagpapakita ng bahagi ng isang larawan sa isang anggulo na may bilugan na mga gilid. Ang pagkakasunud-sunod ng mga operasyon ay mahalaga: unang itakda ang lugar ng pag-clip, pagkatapos ay ilapat ang transformasyon, pagkatapos ay iguhit ang nilalaman. Inirerekomenda ng Apple na bawasan ang bilang ng mga pagbabago sa CTM (Current Transformation Matrix) sa rendering loop.

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

    // lugar ng pag-clip — bilog
    ctx.addEllipse(in: CGRect(x: 50, y: 50, width: 200, height: 200))
    ctx.clip()

    // transformasyon ng nilalaman
    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()
}

Halimbawa ng Pagguhit sa CGContext

Tingnan natin ang isang kumpletong halimbawa ng paglikha ng isang gradient diagram gamit ang CGContext. Ang diagram ay may kasamang tatlong sektor na may iba’t ibang kulay na may gradient fill at mga text label. Ang code ay nagpapakita ng kombinasyon ng saveGState, clip, gradient, at text rendering sa isang konteksto.

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

            // label ng teksto
            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
        }
    }
}

Sa halimbawang ito, ang bawat sektor ng diagram ay iginuhit sa sarili nitong saveGState/restoreGState block. Ang approach na ito ay ginagarantiyahan na ang mga setting ng kulay at path para sa isang sektor ay hindi makakaapekto sa iba. Ang paraan ng addArc ay lumilikha ng isang arko mula sa simula hanggang sa dulo ng anggulo, isinasara ng closePath ang sektor patungo sa gitna. Ang label ng teksto ay inilalagay sa gitnang linya ng anggulo ng sektor gamit ang trigonometric functions na cos at sin para sa pagkalkula ng posisyon.

Upang mapabuti ang pagganap sa madalas na pag-redraw, inirerekomenda ang pag-cache ng mga kalkulasyon ng anggulo at posisyon sa isang hiwalay na array. Ang CGContext ay nagsasagawa ng lahat ng operasyon sa CPU, kaya ang mga kumplikadong eksena na may dose-dosenang mga sektor ay maaaring mangailangan ng optimization — halimbawa, paunang rasterization sa CGLayer o paggamit ng Metal para sa GPU acceleration. Para sa karamihan ng mga UI task na may 5–10 elemento, ang pagganap ng CGContext ay nananatiling katanggap-tanggap.

Mga Madalas Itanong

Paano makukuha ang kasalukuyang CGContext sa iOS?

Tawagan ang UIGraphicsGetCurrentContext() sa loob ng draw(_:) na pamamaraan ng UIView o sa loob ng UIGraphicsBeginImageContextWithOptions block. Para sa mga CALayer layer, gamitin ang draw(in:) ng CALayerDelegate na tumatanggap ng handa nang konteksto.

Ano ang pagkakaiba sa pagitan ng fillPath at strokePath?

fillPath ay pumupuno sa panloob na lugar ng kasalukuyang path na may kulay mula sa setFillColor. strokePath ay gumuhit ng linya kasama ang path na may mga parameter na setStrokeColor, setLineWidth, at setLineCap. Ang parehong operasyon ay isinasagawa nang sunud-sunod: una fill, pagkatapos stroke kung kinakailangan.

Ano ang bitmap CGContext?

Bitmap CGContext — isang konteksto na nilikha sa pamamagitan ng CGBitmapContextCreate na gumuhit sa isang memory buffer sa halip na sa screen. Ginagamit para sa background image generation, graphic processing nang hindi ipinapakita, at paglikha ng mga texture para sa Metal o OpenGL.

Paano i-reset ang lahat ng setting ng CGContext?

Ang Core Graphics ay hindi nagbibigay ng paraan upang i-reset ang lahat ng setting. Gamitin ang saveGState bago ang mga pagbabago at restoreGState upang bumalik sa orihinal na estado. Bilang alternatibo, maaari kang lumikha ng isang bagong konteksto na may parehong mga parameter.

Bakit hindi lumalabas ang gradient sa loob ng hugis?

Bago tawagan ang drawLinearGradient, itakda ang lugar ng pag-clip sa pamamagitan ng clip sa nais na path. Kung walang clip, pupunuin ng gradient ang buong konteksto. Pagkakasunud-sunod: addPath → clip → drawLinearGradient — ginagarantiyahan ang gradient sa loob ng hugis.

Buod

  • CGContext — ang sentral na bagay ng Core Graphics para sa lahat ng 2D na operasyon ng pagguhit sa iOS at macOS.
  • saveGState at restoreGState namamahala sa stack ng estado ng konteksto, pumipigil sa mga side effect.
  • setFillColor at setStrokeColor nagtatakda ng mga kulay ng fill at stroke sa pamamagitan ng CGColorRef.
  • addPath, strokePath, fillPath gumagana sa mga arbitraryong CGPath contour.
  • clip naglilimita sa lugar ng pagguhit sa kasalukuyang path para sa mga maskara at pag-round.
  • translateCTM, scaleCTM, rotateCTM nagbabago ng coordinate system ng konteksto.
  • Lahat ng operasyon ng CGContext ay isinasagawa sa CPU — para sa kumplikadong graphics, gamitin ang CGLayer o Metal.

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din