CGContext στο iOS — τι είναι, μέθοδοι και πώς να διαχειριστείτε το περιβάλλον σχεδίασης

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-07-21 Χρόνος ανάγνωσης: 9 λεπ

CGContext — το βασικό αντικείμενο του Core Graphics για την εκτέλεση εντολών 2D σχεδίασης σε iOS και macOS. Αποτελεί ένα γραφικό περιβάλλον που αποθηκεύει την τρέχουσα κατάσταση: χρώμα γεμίσματος, πάχος γραμμής, μετασχηματισμό, περιοχή αποκοπής και γραμματοσειρές. Όλες οι λειτουργίες σχεδίασης — γραμμές, ορθογώνια, κείμενο, εικόνες — εκτελούνται μέσω του CGContext. Σύμφωνα με το Apple Developer Documentation, 2026, το CGContext αποτελεί το θεμέλιο όλων των raster και vector γραφικών στο οικοσύστημα της 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 για εργασία με raster εικόνες στη μνήμη, PDF context για δημιουργία εγγράφων PDF, window context για απόδοση στην οθόνη (παρέχεται από το UIView στο draw(_:)). Στο iOS, οι προγραμματιστές συνήθως εργάζονται με το περιβάλλον που λαμβάνεται από το UIGraphicsGetCurrentContext() μέσα στη μέθοδο draw(_:) ή από το UIGraphicsBeginImageContextWithOptions για offline απόδοση.

Το περιβάλλον εφαρμόζει όλες τις ρυθμίσεις μέσω στοίβας καταστάσεων — ο προγραμματιστής μπορεί να αποθηκεύσει την τρέχουσα κατάσταση (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 προσθέτει μια κυβική καμπύλη Bézier, 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, επομένως σύνθετες σκηνές με δεκάδες τομείς μπορεί να απαιτούν βελτιστοποίηση — για παράδειγμα, προκαταρκτική rasterization σε 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, το οποίο σχεδιάζει σε buffer μνήμης αντί για οθόνη. Χρησιμοποιείται για παραγωγή εικόνων στο παρασκήνιο, επεξεργασία γραφικών χωρίς εμφάνιση και δημιουργία υφών για 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. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης