CAShapeLayer — είναι μια υποκλάση της CALayer που προορίζεται για υλικό απόδοσης διανυσματικών περιγραμμάτων στην GPU. Σε αντίθεση με τη βασική CALayer που λειτουργεί με ψηφιδωτές εικόνες μέσω contents, η CAShapeLayer αποδίδει αυθαίρετα σχήματα που ορίζονται μέσω CGPath χωρίς δημιουργία ξεχωριστού offscreen buffer. Σύμφωνα με το Apple QuartzCore Documentation, 2025, η CAShapeLayer χρησιμοποιεί επιτάχυνση υλικού για εξομάλυνση άκρων και υποστηρίζει κινούμενα σχέδια path, strokeStart και strokeEnd. Είναι το τυπικό εργαλείο για δημιουργία εικονιδίων, δεικτών προόδου και μασκών στο iOS.
Κύρια Σημεία
CAShapeLayer — είναι ένα εξειδικευμένο στρώμα για απόδοση διανυσματικών γραφικών, που εισήχθη στο iOS 3.0. Σε αντίθεση με την CALayer που αποθηκεύει ψηφιδωτή εικόνα, η CAShapeLayer αποθηκεύει τη μαθηματική περιγραφή του περιγράμματος — CGPath — και την αποδίδει απευθείας στην GPU. Αυτό επιτρέπει κλιμάκωση του σχήματος χωρίς απώλεια ποιότητας και κίνηση των ιδιοτήτων του χωρίς επαναπόδοση περιεχομένου.
Αρχιτεκτονικά, η CAShapeLayer κληρονομεί όλες τις δυνατότητες της CALayer: σκιές, όρια, μετασχηματισμοί, μάσκες. Αλλά προσθέτει συγκεκριμένες ιδιότητες για εργασία με περιγράμματα: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, miterLimit, strokeStart, strokeEnd και fillRule. Κάθε μία από αυτές τις ιδιότητες μπορεί να κινηθεί μέσω CABasicAnimation.
Σύμφωνα με το Apple Documentation, η CAShapeLayer χρησιμοποιεί επιτάχυνση υλικού κατά την απόδοση. Σε αντίθεση με τη σχεδίαση μέσω Core Graphics στο drawRect:, όπου η CPU αποδίδει το περίγραμμα σε ψηφιδωτό περιβάλλον, η CAShapeLayer στέλνει εντολές απευθείας στην GPU μέσω Metal. Αποτέλεσμα — υψηλότερη απόδοση, ειδικά κατά τη διάρκεια κίνησης.
Η CAShapeLayer είναι ιδιαίτερα χρήσιμη για στοιχεία διεπαφής που αλλάζουν σχήμα ως απόκριση σε ενέργειες χρήστη: δείκτες προόδου, γραφήματα, εικονίδια tab-bar, μάσκες για κινούμενο σχέδιο εμφάνισης περιεχομένου.
Η διαδικασία απόδοσης της CAShapeLayer διαφέρει από τη βασική CALayer. Αντί να αποθηκεύει ψηφιδωτό buffer με pixel, η CAShapeLayer στέλνει στην GPU την περιγραφή κορυφής του περιγράμματος — ένα σύνολο σημείων, καμπυλών Bezier και τμημάτων. Η GPU ψηφιοποιεί αυτό το περίγραμμα σε ένα πέρασμα, εφαρμόζοντας το χρώμα γεμίσματος και περιγράμματος στο στάδιο του fragment shader.
Αυτή η προσέγγιση δίνει δύο πλεονεκτήματα: κλιμάκωση χωρίς απώλεια ποιότητας (τα διανυσματικά γραφικά παραμένουν ευκρινή σε οποιαδήποτε ανάλυση) και αποδοτική κίνηση — όταν αλλάζει το path, η GPU υπολογίζει μόνο τα αλλαγμένα pixel, όχι ολόκληρη την οθόνη.
path — η κεντρική ιδιότητα της CAShapeLayer που δέχεται CGPath. Το περίγραμμα μπορεί να περιέχει γραμμές, τόξα, καμπύλες Bezier και ορθογώνια. Δημιουργείται μέσω UIBezierPath σε Swift ή CGPath σε Core Graphics. Παράδειγμα: UIBezierPath(roundedRect: rect, cornerRadius: 16).cgPath δημιουργεί στρογγυλεμένο ορθογώνιο.
Η ιδιότητα lineDashPattern επιτρέπει δημιουργία διακεκομμένων γραμμών. Δέχεται πίνακα αριθμών: [6, 3] σημαίνει 6 σημεία γραμμής και 3 σημεία διαστήματος. Το lineDashPhase ορίζει μετατόπιση μοτίβου και μπορεί να κινηθεί για εφέ κινούμενης διακεκομμένης γραμμής.
Η επιλογή μεταξύ CAShapeLayer και βασικής CALayer εξαρτάται από τον τύπο περιεχομένου. Αν το στοιχείο είναι ορθογώνια περιοχή με φόντο, όριο και σκιά — αρκεί η CALayer. Αν το στοιχείο έχει αυθαίρετο σχήμα, απαιτεί κίνηση περιγράμματος ή κλιμάκωση χωρίς απώλεια ποιότητας — η CAShapeLayer είναι προτιμότερη.
Η απόδοση επίσης διαφέρει. Η CALayer με cornerRadius και masksToBounds δημιουργεί offscreen buffer για περικοπή περιεχομένου, προσθέτοντας 2–5 ms ανά καρέ. Η CAShapeLayer δεν απαιτεί offscreen buffer — η περικοπή γίνεται σε επίπεδο vertex shader. Για στοιχεία με σύνθετη μάσκα, η CAShapeLayer μπορεί να είναι 2–3 φορές ταχύτερη.
Ο συνδυασμός CAShapeLayer με άλλα στρώματα είναι κοινό μοτίβο. Για παράδειγμα, η CAGradientLayer χρησιμοποιεί CAShapeLayer ως μάσκα για δημιουργία σχήματος με γέμισμα διαβάθμισης. Αυτή η προσέγγιση δίνει και διανυσματική ποιότητα και γέμισμα διαβάθμισης χωρίς απώλεια απόδοσης.
Κίνηση path — μία από τις ισχυρότερες δυνατότητες της CAShapeLayer. Αν και τα δύο περιγράμματα (αρχικό και τελικό) έχουν τον ίδιο αριθμό σημείων ελέγχου και τμημάτων, η Core Animation εκτελεί ομαλή παρεμβολή μεταξύ τους. Αποτέλεσμα — εφέ μεταμόρφωσης ενός σχήματος σε άλλο.
Προϋπόθεση συμβατότητας path: το αρχικό και τελικό UIBezierPath πρέπει να έχουν την ίδια δομή — ο αριθμός κλήσεων moveTo, addLine, addCurve και addQuadCurve πρέπει να συμπίπτει. Αν η δομή διαφέρει, η κίνηση θα είναι στιγμιαία, χωρίς παρεμβολή.
Σύμφωνα με το Apple WWDC 2024, ο συνδυασμός strokeStart και strokeEnd είναι το πιο συχνά χρησιμοποιούμενο μοτίβο κίνησης CAShapeLayer. Η κίνηση strokeEnd από 0.0 έως 1.0 δημιουργεί εφέ σχεδίασης περιγράμματος από την αρχή έως το τέλος. Χρησιμοποιείται σε δείκτες φόρτωσης, κινήσεις εμφάνισης γραφημάτων και προσαρμοσμένες μεταβάσεις μεταξύ οθονών.
Για δημιουργία εφέ παλμού, κίνησε ταυτόχρονα strokeEnd και opacity με διαφορετικές συναρτήσεις χρονισμού. Για εφέ κινούμενης διακεκομμένης γραμμής, κίνησε lineDashPhase με σταθερό lineDashPattern. Και οι δύο τεχνικές υλοποιούνται μέσω CABasicAnimation χωρίς συμμετοχή CPU.
Η CAShapeLayer χρησιμοποιείται συχνά ως mask για άλλα στρώματα. Για παράδειγμα, για κίνηση εμφάνισης περιεχομένου: στην αρχή mask.path είναι ορθογώνιο μηδενικού μεγέθους, στο τέλος — πλήρες μέγεθος. Η Core Animation παρεμβάλλει το path και το περιεχόμενο αποκαλύπτεται ομαλά.
Αυτό το μοτίβο χρησιμοποιείται στο iOS για κίνηση ανοίγματος καρτών, εμφάνισης παραθύρων και μεταβάσεων μεταξύ view controller. Σε αντίθεση με την κίνηση alpha, η κίνηση μέσω μάσκας CAShapeLayer δίνει πιο φυσικό εφέ εμφάνισης με αυθαίρετο σχήμα.
Πρώτο παράδειγμα — δημιουργία κυκλικού δείκτη προόδου με κίνηση strokeEnd. Αυτό είναι ένα τυπικό στοιχείο UI που δείχνει τις βασικές δυνατότητες της CAShapeLayer:
func createProgressIndicator(in view: UIView) -> CAShapeLayer {
let circlePath = UIBezierPath(
arcCenter: CGPoint(x: 50, y: 50),
radius: 40,
startAngle: -.pi / 2,
endAngle: 3 * .pi / 2,
clockwise: true
)
let trackLayer = CAShapeLayer()
trackLayer.path = circlePath.cgPath
trackLayer.strokeColor = UIColor.systemGray5.cgColor
trackLayer.fillColor = nil
trackLayer.lineWidth = 8
view.layer.addSublayer(trackLayer)
let progressLayer = CAShapeLayer()
progressLayer.path = circlePath.cgPath
progressLayer.strokeColor = UIColor.systemBlue.cgColor
progressLayer.fillColor = nil
progressLayer.lineWidth = 8
progressLayer.lineCap = .round
progressLayer.strokeEnd = 0
view.layer.addSublayer(progressLayer)
return progressLayer
}
// Κίνηση στο 75%
progressLayer.animateStrokeEnd(to: 0.75, duration: 1.5)
Δεύτερο παράδειγμα — κίνηση μεταμόρφωσης μεταξύ κύκλου και τετραγώνου. Και τα δύο UIBezierPath έχουν συμβατή δομή:
let morphLayer = CAShapeLayer()
morphLayer.fillColor = UIColor.systemPurple.cgColor
morphLayer.frame = rect
let circlePath = UIBezierPath(roundedRect: rect, cornerRadius: rect.width / 2)
let squarePath = UIBezierPath(roundedRect: rect, cornerRadius: 0)
morphLayer.path = circlePath.cgPath
let morphAnimation = CABasicAnimation(keyPath: "path")
morphAnimation.toValue = squarePath.cgPath
morphAnimation.duration = 0.6
morphAnimation.autoreverses = true
morphAnimation.repeatCount = .infinity
morphLayer.add(morphAnimation, forKey: "morph")
Τρίτο παράδειγμα — μάσκα με CAShapeLayer για κίνηση εμφάνισης περιεχομένου. Η μάσκα επεκτείνεται από το κέντρο προς τις άκρες:
func revealContent(_ view: UIView) {
let maskLayer = CAShapeLayer()
let size = view.bounds.size.width * 1.5
let center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
let initialPath = UIBezierPath(arcCenter: center, radius: 0, startAngle: 0, endAngle: .pi * 2, clockwise: true)
let finalPath = UIBezierPath(arcCenter: center, radius: size, startAngle: 0, endAngle: .pi * 2, clockwise: true)
maskLayer.path = initialPath.cgPath
view.layer.mask = maskLayer
let animation = CABasicAnimation(keyPath: "path")
animation.toValue = finalPath.cgPath
animation.duration = 0.4
animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
maskLayer.add(animation, forKey: "reveal")
maskLayer.path = finalPath.cgPath
}
Συχνές Ερωτήσεις
Το drawRect χρησιμοποιεί CPU για απόδοση σε ψηφιδωτό περιβάλλον — είναι αργό για κινήσεις. Η CAShapeLayer αποδίδει το περίγραμμα στην GPU, δίνοντας 60 FPS σε κίνηση path, strokeEnd και μετασχηματισμών. Επιπλέον, η CAShapeLayer δεν απαιτεί επαναπόδοση κατά αλλαγή μεγέθους — το σχήμα κλιμακώνεται διανυσματικά.
Η ομαλή κίνηση path απαιτεί ίδια δομή αρχικού και τελικού UIBezierPath. Ο αριθμός κλήσεων moveTo, addLine, addCurve πρέπει να συμπίπτει. Χρησιμοποίησε UIBezierPath με ίδιο αριθμό τμημάτων για αρχικό και τελικό σχήμα.
Όρισε lineDashPattern — πίνακα αριθμών που εναλλάξ καθορίζουν μήκος γραμμής και διαστήματος. Για παράδειγμα, [8, 4] δημιουργεί γραμμές 8pt με διαστήματα 4pt. Για κινούμενη διακεκομμένη γραμμή, κίνησε lineDashPhase μέσω CABasicAnimation με γραμμική συνάρτηση χρονισμού.
Ναι, αυτό είναι ένα από τα κύρια σενάρια. Ανέθεσε CAShapeLayer στην ιδιότητα mask οποιασδήποτε CALayer, συμπεριλαμβανομένων CAGradientLayer και άλλων υποκλάσεων. Η κίνηση path της μάσκας δημιουργεί εφέ ομαλής εμφάνισης περιεχομένου μέσω σχήματος αυθαίρετης μορφής.
Δημιούργησε CAGradientLayer και όρισε mask = CAShapeLayer με το επιθυμητό path. Η διαβάθμιση θα είναι ορατή μόνο εντός του περιγράμματος της μάσκας. Αυτό το μοτίβο συνδυάζει τα πλεονεκτήματα διανυσματικού σχήματος CAShapeLayer με γέμισμα διαβάθμισης CAGradientLayer.
Περίληψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης