CGContext — το βασικό αντικείμενο του Core Graphics για την εκτέλεση εντολών 2D σχεδίασης σε iOS και macOS. Αποτελεί ένα γραφικό περιβάλλον που αποθηκεύει την τρέχουσα κατάσταση: χρώμα γεμίσματος, πάχος γραμμής, μετασχηματισμό, περιοχή αποκοπής και γραμματοσειρές. Όλες οι λειτουργίες σχεδίασης — γραμμές, ορθογώνια, κείμενο, εικόνες — εκτελούνται μέσω του CGContext. Σύμφωνα με το Apple Developer Documentation, 2026, το CGContext αποτελεί το θεμέλιο όλων των raster και vector γραφικών στο οικοσύστημα της Apple.
Βασικά Σημεία
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, η σωστή χρήση της στοίβας καταστάσεων βελτιώνει την αναγνωσιμότητα του κώδικα και αποτρέπει οπτικά τεχνουργήματα.
CGContextSaveGState τοποθετεί ένα αντίγραφο της τρέχουσας κατάστασης του περιβάλλοντος στη στοίβα. Αυτή η κατάσταση περιλαμβάνει όλες τις ρυθμίσεις: χρώματα, πάχος γραμμής, μετασχηματισμό, σκιές, περιοχή αποκοπής, γραμματοσειρές. Μετά την τροποποίηση των παραμέτρων, η κλήση CGContextRestoreGState επαναφέρει το περιβάλλον στην αποθηκευμένη κατάσταση, ακυρώνοντας όλες τις ενδιάμεσες αλλαγές. Η στοίβα μπορεί να περιέχει έως 32 καταστάσεις στο iOS.
Κατά τη σχεδίαση μιας ομάδας στοιχείων με διαφορετικά στυλ (π.χ. πολύχρωμοι τομείς διαγράμματος), η στοίβα καταστάσεων εξαλείφει την ανάγκη απομνημόνευσης και επαναφοράς κάθε παραμέτρου χειροκίνητα. Χωρίς saveGState/restoreGState, ο προγραμματιστής θα έπρεπε να επαναφέρει το χρώμα, τη σκιά και το μετασχηματισμό μετά από κάθε στοιχείο. Η χρήση της στοίβας μειώνει τον κώδικα και αποκλείει σφάλματα επαναφοράς.
Είναι σημαντικό να τηρείται ισορροπία αποθηκεύσεων και επαναφορών — κάθε saveGState πρέπει να έχει ένα αντίστοιχο restoreGState. Η παραβίαση της ισορροπίας οδηγεί σε διαρροή καταστάσεων ή πρόωρη επαναφορά, προκαλώντας απρόβλεπτη εμφάνιση. Ο στατικός αναλυτής του Xcode δεν ελέγχει την ισορροπία της στοίβας CGContext, επομένως η ευθύνη για την ορθότητα ανήκει στον προγραμματιστή. Συνιστάται η ομαδοποίηση ζευγών σε do/finally μπλοκ.
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 για βελτίωση της απόδοσης.
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.
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) σε βρόχο απόδοσης.
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. Το διάγραμμα περιλαμβάνει τρεις τομείς διαφορετικού χρώματος με γέμισμα διαβάθμισης και ετικέτες κειμένου. Ο κώδικας δείχνει το συνδυασμό saveGState, clip, διαβαθμίσεων και απόδοσης κειμένου σε ένα περιβάλλον.
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 παραμένει αποδεκτή.
Συχνές Ερωτήσεις
Καλέστε το UIGraphicsGetCurrentContext() μέσα στη μέθοδο draw(_:) του UIView ή μέσα στο μπλοκ UIGraphicsBeginImageContextWithOptions. Για επίπεδα CALayer, χρησιμοποιήστε το draw(in:) του εκπροσώπου CALayerDelegate, το οποίο λαμβάνει ένα έτοιμο περιβάλλον.
fillPath γεμίζει την εσωτερική περιοχή του τρέχοντος περιγράμματος με το χρώμα από το setFillColor. strokePath σχεδιάζει μια γραμμή κατά μήκος του περιγράμματος με τις παραμέτρους setStrokeColor, setLineWidth και setLineCap. Και οι δύο λειτουργίες εκτελούνται διαδοχικά: πρώτα fill, στη συνέχεια stroke εάν χρειάζεται.
Bitmap CGContext — ένα περιβάλλον που δημιουργείται μέσω CGBitmapContextCreate, το οποίο σχεδιάζει σε buffer μνήμης αντί για οθόνη. Χρησιμοποιείται για παραγωγή εικόνων στο παρασκήνιο, επεξεργασία γραφικών χωρίς εμφάνιση και δημιουργία υφών για Metal ή OpenGL.
Το Core Graphics δεν παρέχει μέθοδο επαναφοράς όλων των ρυθμίσεων. Χρησιμοποιήστε saveGState πριν από αλλαγές και restoreGState για επαναφορά στην αρχική κατάσταση. Εναλλακτικά, μπορείτε να δημιουργήσετε ένα νέο περιβάλλον με τις ίδιες παραμέτρους.
Πριν καλέσετε το drawLinearGradient, ορίστε την περιοχή αποκοπής μέσω clip στο επιθυμητό περίγραμμα. Χωρίς clip, η διαβάθμιση γεμίζει ολόκληρο το περιβάλλον. Η σειρά: addPath → clip → drawLinearGradient — εγγυάται τη διαβάθμιση εντός του σχήματος.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης