CAShapeLayer — ce este, proprietăți și crearea formelor

Autor: IT Sectr Publicat: 2026-06-12 Timp de citire: 10 min

CAShapeLayer — este o subclasă CALayer destinată randării hardware a contururilor vectoriale pe GPU. Spre deosebire de CALayer de bază, care lucrează cu imagini raster prin contents, CAShapeLayerrandează forme arbitrare definite prin CGPath fără a crea un buffer offscreen separat. Conform Apple QuartzCore Documentation, 2025, CAShapeLayer utilizează accelerarea hardware pentru netezirea marginilor și suportă animația path, strokeStart și strokeEnd. Este instrumentul standard pentru crearea de pictograme, indicatoare de progres și măști în iOS.

Principalele puncte

  • CAShapeLayer — subclasă CALayer pentru randarea formelor vectoriale pe GPU prin CGPath.
  • Randarea conturului se face hardware fără a crea un buffer raster intermediar — este mai rapid decât Core Graphics.
  • Proprietățile fillColor, strokeColor, lineWidth, lineCap, lineJoin controlează aspectul formei.
  • Animația path permite transformarea lină a unei forme în alta — o capacitate cheie pentru animațiile UI.
  • strokeStart și strokeEnd sunt animate pentru a crea efectul de desenare a conturului — ideal pentru indicatoarele de încărcare.

Ce este CAShapeLayer?

CAShapeLayer — este un strat specializat pentru randarea graficii vectoriale, introdus în iOS 3.0. Spre deosebire de CALayer, care stochează o imagine raster, CAShapeLayer stochează descrierea matematică a conturului — CGPath — și îl randează direct pe GPU. Acest lucru permite scalarea formei fără pierdere de calitate și animarea proprietăților sale fără re-randarea conținutului.

Arhitectural, CAShapeLayer moștenește toate capacitățile CALayer: umbre, margini, transformări, măști. Dar adaugă proprietăți specifice pentru lucrul cu contururi: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, miterLimit, strokeStart, strokeEnd și fillRule. Fiecare dintre aceste proprietăți poate fi animată prin CABasicAnimation.

Conform Apple Documentation, CAShapeLayer utilizează accelerarea hardware la randare. Spre deosebire de desenarea prin Core Graphics în drawRect:, unde CPU randează conturul într-un context raster, CAShapeLayer trimite comenzi direct pe GPU prin Metal. Rezultat — performanță mai mare, în special în timpul animației.

CAShapeLayer este deosebit de util pentru elementele de interfață care își schimbă forma ca răspuns la acțiunile utilizatorului: indicatoare de progres, grafice, pictograme tab-bar, măști pentru animația de apariție a conținutului.

Cum randează CAShapeLayer conturul pe GPU

Procesul de randare al CAShapeLayer diferă de CALayer de bază. În loc să stocheze un buffer raster cu pixeli, CAShapeLayer trimite GPU-ului descrierea vertex a conturului — un set de puncte, curbe Bezier și segmente. GPU-ul rasterizează acest contur într-o singură trecere, aplicând culoarea de umplere și contur în etapa shader-ului de fragment.

Această abordare oferă două avantaje: scalare fără pierdere de calitate (grafica vectorială rămâne clară la orice rezoluție) și animație eficientă — la schimbarea path, GPU-ul recalculează doar pixelii modificați, nu întregul ecran.

Proprietățile principale CAShapeLayer

path — proprietatea centrală a CAShapeLayer, care primește CGPath. Conturul poate conține linii, arcuri, curbe Bezier și dreptunghiuri. Se creează prin UIBezierPath în Swift sau CGPath în Core Graphics. Exemplu: UIBezierPath(roundedRect: rect, cornerRadius: 16).cgPath creează un dreptunghi cu colțuri rotunjite.

  • fillColor — culoarea de umplere a conturului închis (CGColor). Dacă este nil — fără umplere. Suportă animație.
  • strokeColor — culoarea conturului. Se animează împreună cu lineWidth, creând efectul unui contur care se desenează.
  • lineWidth — grosimea liniei de contur în puncte. Implicit 1.0. Poate fi animată.
  • lineCap — stilul capătului de linie: .butt (tăietură dreaptă), .round (rotunjit), .square (dreptunghiular cu proeminență).
  • lineJoin — stilul îmbinării liniilor: .miter (unghi ascuțit), .round (rotunjit), .bevel (tăiat).
  • strokeStart și strokeEnd — proporția conturului desenat de la 0.0 la 1.0. Animația strokeEnd creează efectul de apariție treptată.
  • fillRule — regula de umplere a contururilor care se intersectează: .nonZero (implicit) sau .evenOdd.
  • miterLimit — lungimea maximă a vârfului la lineJoin = .miter. Previne unghiurile infinit de lungi.

Proprietatea lineDashPattern permite crearea liniilor punctate. Primește un array de numere: [6, 3] înseamnă 6 puncte de linie și 3 puncte de spațiu. lineDashPhase stabilește deplasarea modelului și poate fi animată pentru efectul de linie punctată în mișcare.

CAShapeLayer vs CALayer: când să alegem fiecare

Alegerea între CAShapeLayer și CALayer de bază depinde de tipul conținutului. Dacă elementul este o zonă dreptunghiulară cu fundal, margine și umbră — este suficient CALayer. Dacă elementul are o formă arbitrară, necesită animație a conturului sau scalare fără pierdere de calitate — CAShapeLayer este preferabil.

Performanța diferă de asemenea. CALayer cu cornerRadius și masksToBounds creează un buffer offscreen pentru decuparea conținutului, ceea ce adaugă 2–5 ms per cadru. CAShapeLayer nu necesită buffer offscreen — decuparea se face la nivelul shader-ului de vertex. Pentru elemente cu măști complexe, CAShapeLayer poate fi de 2–3 ori mai rapid.

  • CALayer: elemente dreptunghiulare, fotografii, video, conținut cu colțuri rotunjite (cornerRadius), umbre, margini.
  • CAShapeLayer: pictograme, grafice, bare de progres, măști de formă arbitrară, contururi animate, forme pentru animația de apariție.
  • CATextLayer: text care necesită randare subpixel și cache de glyfi.
  • CAGradientLayer: umpleri gradient — se combină cu CAShapeLayer prin mask pentru a crea forme cu gradient.

Combinarea CAShapeLayer cu alte straturi este un model comun. De exemplu, CAGradientLayer folosește CAShapeLayer ca mască pentru a crea o formă cu umplere gradient. Această abordare oferă atât calitate vectorială, cât și umplere gradient fără pierdere de performanță.

Animația CAShapeLayer: path și stroke

Animația path — una dintre cele mai puternice capacități ale CAShapeLayer. Dacă ambele contururi (inițial și final) au același număr de puncte de control și segmente, Core Animation efectuează o interpolare lină între ele. Rezultat — efectul de morfing al unei forme în alta.

Condiția de compatibilitate path: UIBezierPath inițial și final trebuie să aibă aceeași structură — numărul de apeluri moveTo, addLine, addCurve și addQuadCurve trebuie să coincidă. Dacă structura diferă, animația va fi instantanee, fără interpolare.

Conform Apple WWDC 2024, combinația strokeStart și strokeEnd este cel mai frecvent utilizat model de animație CAShapeLayer. Animația strokeEnd de la 0.0 la 1.0 creează efectul de desenare a conturului de la început la sfârșit. Este folosit în indicatoarele de încărcare, animațiile de apariție a graficelor și tranzițiile personalizate între ecrane.

Pentru a crea un efect de pulsație, animează simultan strokeEnd și opacity cu funcții de timing diferite. Pentru efectul de linie punctată în mișcare, animează lineDashPhase cu lineDashPattern fix. Ambele tehnici se implementează prin CABasicAnimation fără participarea CPU.

Animația ca mască

CAShapeLayer este adesea folosit ca mask pentru alte straturi. De exemplu, pentru animația de apariție a conținutului: la început mask.path este un dreptunghi de dimensiune zero, la final — dimensiunea completă. Core Animation interpolează path, iar conținutul se dezvăluie lin.

Acest model este folosit în iOS pentru animația de desfășurare a cardurilor, apariția ferestrelor modale și tranzițiile între view controllere. Spre deosebire de animația alpha, animația prin masca CAShapeLayer oferă un efect mai natural de apariție cu o formă arbitrară.

Exemple de cod cu CAShapeLayer în Swift

Primul exemplu — crearea unui indicator circular de progres cu animația strokeEnd. Acesta este un element UI standard care demonstrează capacitățile principale ale CAShapeLayer:

swift
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
}

// Animație până la 75%
progressLayer.animateStrokeEnd(to: 0.75, duration: 1.5)

Al doilea exemplu — animația de morfing între cerc și pătrat. Ambele UIBezierPath au o structură compatibilă:

swift
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")

Al treilea exemplu — mască cu CAShapeLayer pentru animația de apariție a conținutului. Masca se extinde de la centru spre margini:

swift
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
}

Întrebări frecvente

Cu ce diferă CAShapeLayer de desenarea în drawRect?

drawRect folosește CPU pentru randarea într-un context raster — este lent pentru animații. CAShapeLayer randează conturul pe GPU, oferind 60 FPS la animația path, strokeEnd și transformări. În plus, CAShapeLayer nu necesită re-randare la schimbarea dimensiunilor — forma se scalează vectorial.

De ce animația path nu funcționează lin?

Animația lină a path necesită aceeași structură a UIBezierPath inițial și final. Numărul de apeluri moveTo, addLine, addCurve trebuie să coincidă. Folosește UIBezierPath cu același număr de segmente pentru forma inițială și finală.

Cum se creează o linie punctată în CAShapeLayer?

Setează lineDashPattern — un array de numere care alternează lungimea liniei și a spațiului. De exemplu, [8, 4] creează linii de 8pt cu spații de 4pt. Pentru linia punctată în mișcare, animează lineDashPhase prin CABasicAnimation cu o funcție de timing liniară.

Poate fi folosit CAShapeLayer ca mască?

Da, acesta este unul dintre scenariile principale. Atribuie CAShapeLayer proprietății mask a oricărui CALayer, inclusiv CAGradientLayer și alte subclase. Animația path a măștii creează efectul de apariție lină a conținutului printr-o formă arbitrară.

Cum se umple o formă cu gradient prin CAShapeLayer?

Creează CAGradientLayer și setează mask acestuia = CAShapeLayer cu path-ul dorit. Gradientul va fi vizibil doar în interiorul conturului măștii. Acest model combină avantajele formei vectoriale CAShapeLayer cu umplerea gradient a CAGradientLayer.

Rezumat

  • CAShapeLayer — subclasă CALayer pentru randarea hardware a contururilor vectoriale pe GPU prin CGPath.
  • Proprietăți cheie: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, strokeStart, strokeEnd.
  • Animația path creează morfingul formelor — necesită aceeași structură a conturului inițial și final.
  • Animația strokeEnd — model standard pentru indicatoarele de progres și desenarea contururilor.
  • CAShapeLayer nu necesită buffer offscreen pentru mascare, spre deosebire de CALayer cu masksToBounds.
  • Folosit ca mască pentru CAGradientLayer, creând forme cu umplere gradient.
  • Pentru linii punctate, folosește lineDashPattern cu animația lineDashPhase pentru efect de mișcare.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și