CAShapeLayer — is een subklasse van CALayer bedoeld voor het hardwarematig renderen van vectorcontouren op de GPU. In tegenstelling tot de basis CALayer, die werkt met rasterafbeeldingen via contents, rendert CAShapeLayer willekeurige vormen die via CGPath zijn gedefinieerd zonder een aparte offscreen-buffer te creëren. Volgens Apple QuartzCore Documentation, 2025 gebruikt CAShapeLayer hardwareversnelling voor het afvlakken van randen en ondersteunt het animatie van path, strokeStart en strokeEnd. Dit is het standaardinstrument voor het maken van pictogrammen, voortgangsindicatoren en masks in iOS.
Belangrijkste punten
CAShapeLayer — is een gespecialiseerde laag voor het renderen van vectorafbeeldingen, geïntroduceerd in iOS 3.0. In tegenstelling tot CALayer, die een rasterafbeelding opslaat, slaat CAShapeLayer de wiskundige beschrijving van een contour op — CGPath — en rendert deze rechtstreeks op de GPU. Dit maakt het mogelijk om de vorm te schalen zonder kwaliteitsverlies en de eigenschappen ervan te animeren zonder de inhoud opnieuw te renderen.
Architecturaal gezien erft CAShapeLayer alle mogelijkheden van CALayer: schaduwen, randen, transformaties, masks. Maar het voegt specifieke eigenschappen toe voor het werken met contouren: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, miterLimit, strokeStart, strokeEnd en fillRule. Elk van deze eigenschappen kan worden geanimeerd via CABasicAnimation.
Volgens Apple Documentation gebruikt CAShapeLayer hardwareversnelling bij het renderen. In tegenstelling tot tekenen via Core Graphics in drawRect:, waar de CPU de contour in een rastercontext rendert, stuurt CAShapeLayer commando's rechtstreeks naar de GPU via Metal. Resultaat — hogere prestaties, vooral tijdens animatie.
CAShapeLayer is vooral nuttig voor interface-elementen die van vorm veranderen als reactie op gebruikersacties: voortgangsindicatoren, grafieken, tab-bar-pictogrammen, masks voor het animeren van het verschijnen van inhoud.
Het renderproces van CAShapeLayer verschilt van de basis CALayer. In plaats van een rasterbuffer met pixels op te slaan, stuurt CAShapeLayer de vertex-beschrijving van de contour naar de GPU — een set punten, Bezier-curven en segmenten. De GPU rasteriseert deze contour in één enkele doorgang, waarbij de vul- en lijnkleur wordt toegepast in de fase van de fragment-shader.
Deze aanpak biedt twee voordelen: schalen zonder kwaliteitsverlies (vectorafbeeldingen blijven scherp bij elke resolutie) en efficiënte animatie — bij wijziging van path herberekent de GPU alleen de gewijzigde pixels, niet het hele scherm.
path — de centrale eigenschap van CAShapeLayer, die CGPath accepteert. De contour kan lijnen, bogen, Bezier-curven en rechthoeken bevatten. Wordt gemaakt via UIBezierPath in Swift of CGPath in Core Graphics. Voorbeeld: UIBezierPath(roundedRect: rect, cornerRadius: 16).cgPath maakt een afgeronde rechthoek.
De eigenschap lineDashPattern maakt het mogelijk om stippellijnen te maken. Het accepteert een array van getallen: [6, 3] betekent 6 punten lijn en 3 punten spatie. lineDashPhase bepaalt de verschuiving van het patroon en kan worden geanimeerd voor het effect van een bewegende stippellijn.
De keuze tussen CAShapeLayer en de basis CALayer hangt af van het type inhoud. Als het element een rechthoekig gebied is met achtergrond, rand en schaduw — is CALayer voldoende. Als het element een willekeurige vorm heeft, animatie van de contour of schaling zonder kwaliteitsverlies vereist — heeft CAShapeLayer de voorkeur.
Ook de prestaties verschillen. CALayer met cornerRadius en masksToBounds maakt een offscreen-buffer voor het bijsnijden van inhoud, wat 2–5 ms per frame toevoegt. CAShapeLayer heeft geen offscreen-buffer nodig — bijsnijden gebeurt op het niveau van de vertex-shader. Voor elementen met complexe masks kan CAShapeLayer 2–3 keer sneller zijn.
Het combineren van CAShapeLayer met andere lagen is een veelvoorkomend patroon. Bijvoorbeeld, CAGradientLayer gebruikt CAShapeLayer als mask om een vorm met verloopvulling te maken. Deze aanpak biedt zowel vectorkwaliteit als verloopvulling zonder prestatieverlies.
Path-animatie — een van de krachtigste mogelijkheden van CAShapeLayer. Als beide contouren (begin en eind) hetzelfde aantal controlepunten en segmenten hebben, voert Core Animation een vloeiende interpolatie tussen hen uit. Resultaat — het effect van het vervormen van de ene vorm in de andere.
Voorwaarde voor path-compatibiliteit: de begin- en eind-UIBezierPath moeten dezelfde structuur hebben — het aantal aanroepen van moveTo, addLine, addCurve en addQuadCurve moet overeenkomen. Als de structuur verschilt, zal de animatie onmiddellijk zijn, zonder interpolatie.
Volgens Apple WWDC 2024 is de combinatie van strokeStart en strokeEnd het meest gebruikte animatiepatroon van CAShapeLayer. Animatie van strokeEnd van 0.0 naar 1.0 creëert het effect van het tekenen van een contour van begin tot eind. Dit wordt gebruikt in laadindicatoren, animaties van het verschijnen van grafieken en aangepaste overgangen tussen schermen.
Om een pulseereffect te creëren, animeer je tegelijkertijd strokeEnd en opacity met verschillende timing-functies. Voor het effect van een bewegende stippellijn, animeer je lineDashPhase met een vast lineDashPattern. Beide technieken worden geïmplementeerd via CABasicAnimation zonder tussenkomst van de CPU.
CAShapeLayer wordt vaak gebruikt als mask voor andere lagen. Bijvoorbeeld, voor het animeren van het verschijnen van inhoud: in het begin is mask.path een rechthoek met nul-formaat, aan het eind — volledig formaat. Core Animation interpoleert path en de inhoud wordt vloeiend onthuld.
Dit patroon wordt in iOS gebruikt voor het animeren van het uitvouwen van kaarten, het verschijnen van modale vensters en overgangen tussen view controllers. In tegenstelling tot alpha-animatie, geeft animatie via een CAShapeLayer-mask een natuurlijker verschijningseffect met een willekeurige vorm.
Eerste voorbeeld — het maken van een ronde voortgangsindicator met strokeEnd-animatie. Dit is een standaard UI-element dat de belangrijkste mogelijkheden van CAShapeLayer demonstreert:
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
}
// Animeer naar 75%
progressLayer.animateStrokeEnd(to: 0.75, duration: 1.5)
Tweede voorbeeld — vervormingsanimatie tussen een cirkel en een vierkant. Beide UIBezierPath hebben een compatibele structuur:
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")
Derde voorbeeld — mask met CAShapeLayer voor het animeren van het verschijnen van inhoud. Het mask breidt zich uit van het midden naar de randen:
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
}
Veelgestelde vragen
drawRect gebruikt de CPU voor rendering in een rastercontext — dit is traag voor animaties. CAShapeLayer rendert de contour op de GPU, wat 60 FPS geeft bij animatie van path, strokeEnd en transformaties. Bovendien vereist CAShapeLayer geen herrendering bij formaatwijzigingen — de vorm wordt vectoriëel geschaald.
Vloeiende path-animatie vereist dezelfde structuur van de begin- en eind-UIBezierPath. Het aantal aanroepen van moveTo, addLine, addCurve moet overeenkomen. Gebruik UIBezierPath met hetzelfde aantal segmenten voor de begin- en eindvorm.
Stel lineDashPattern in — een array van getallen die afwisselend de lengte van lijn en spatie bepalen. Bijvoorbeeld, [8, 4] creëert lijnen van 8pt met spaties van 4pt. Voor een bewegende stippellijn, animeer je lineDashPhase via CABasicAnimation met een lineaire timing-functie.
Ja, dit is een van de belangrijkste scenario's. Wijs CAShapeLayer toe aan de eigenschap mask van elke CALayer, inclusief CAGradientLayer en andere subklassen. Animatie van het mask-path creëert het effect van vloeiend verschijnen van inhoud door een vorm met willekeurige vorm.
Maak een CAGradientLayer en stel de mask ervan in op CAShapeLayer met het gewenste path. Het verloop is alleen zichtbaar binnen de contour van het mask. Dit patroon combineert de voordelen van de vectorvorm van CAShapeLayer met de verloopvulling van CAGradientLayer.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook