CAShapeLayer — co to jest, właściwości i tworzenie kształtów

Autor: IT Sectr Opublikowano: 2026-06-12 Czas czytania: 10 min

CAShapeLayer — to podklasa CALayer przeznaczona do sprzętowego renderowania wektorowych konturów na GPU. W przeciwieństwie do podstawowego CALayer, który działa na obrazach rastrowych przez contents, CAShapeLayer renderuje dowolne kształty zadane przez CGPath bez tworzenia osobnego bufora offscreen. Według Apple QuartzCore Documentation, 2025, CAShapeLayer wykorzystuje sprzętowe przyspieszenie do wygładzania krawędzi i obsługuje animację path, strokeStart i strokeEnd. To standardowe narzędzie do tworzenia ikon, wskaźników postępu i masek w iOS.

Najważniejsze

  • CAShapeLayer — podklasa CALayer do renderowania wektorowych kształtów na GPU przez CGPath.
  • Renderowanie konturu odbywa się sprzętowo bez tworzenia pośredniego bufora rastrowego — jest szybsze niż Core Graphics.
  • Właściwości fillColor, strokeColor, lineWidth, lineCap, lineJoin kontrolują wygląd kształtu.
  • Animacja path pozwala płynnie morfinować jeden kształt w drugi — kluczowa możliwość dla animacji UI.
  • strokeStart i strokeEnd są animowane do tworzenia efektu rysowania konturu — idealne dla wskaźników ładowania.

Co to jest CAShapeLayer?

CAShapeLayer — to specjalizowana warstwa do renderowania grafiki wektorowej, wprowadzona w iOS 3.0. W przeciwieństwie do CALayer, który przechowuje obraz rastrowy, CAShapeLayer przechowuje matematyczny opis konturu — CGPath — i renderuje go bezpośrednio na GPU. Umożliwia to skalowanie kształtu bez utraty jakości i animowanie jego właściwości bez przerysowywania zawartości.

Architektonicznie CAShapeLayer dziedziczy wszystkie możliwości CALayer: cienie, granice, transformacje, maski. Ale dodaje specyficzne właściwości do pracy z konturami: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, miterLimit, strokeStart, strokeEnd i fillRule. Każda z tych właściwości może być animowana przez CABasicAnimation.

Według Apple Documentation, CAShapeLayer wykorzystuje sprzętowe przyspieszenie podczas renderowania. W przeciwieństwie do rysowania przez Core Graphics w drawRect:, gdzie CPU renderuje kontur w kontekście rastrowym, CAShapeLayer wysyła polecenia bezpośrednio na GPU przez Metal. Rezultat — wyższa wydajność, szczególnie podczas animacji.

CAShapeLayer jest szczególnie przydatny dla elementów interfejsu, które zmieniają kształt w odpowiedzi na działania użytkownika: wskaźniki postępu, wykresy, ikony tab-bara, maski do animacji pojawiania się treści.

Jak CAShapeLayer renderuje kontur na GPU

Proces renderowania CAShapeLayer różni się od podstawowego CALayer. Zamiast przechowywać bufor rastrowy z pikselami, CAShapeLayer przekazuje GPU wierzchołkowy opis konturu — zbiór punktów, krzywych Beziera i odcinków. GPU rasteryzuje ten kontur w jednym przebiegu, stosując kolor wypełnienia i obrysu na etapie shadera fragmentów.

To podejście daje dwie zalety: skalowanie bez utraty jakości (grafika wektorowa pozostaje ostra przy każdej rozdzielczości) i efektywną animację — przy zmianie path GPU przelicza tylko zmienione piksele, a nie cały ekran.

Główne właściwości CAShapeLayer

path — centralna właściwość CAShapeLayer, przyjmująca CGPath. Kontur może zawierać linie, łuki, krzywe Beziera i prostokąty. Tworzony przez UIBezierPath w Swift lub CGPath w Core Graphics. Przykład: UIBezierPath(roundedRect: rect, cornerRadius: 16).cgPath tworzy zaokrąglony prostokąt.

  • fillColor — kolor wypełnienia zamkniętego konturu (CGColor). Jeśli nil — brak wypełnienia. Obsługuje animację.
  • strokeColor — kolor obrysu konturu. Animowany razem z lineWidth, tworząc efekt rysującego się konturu.
  • lineWidth — grubość linii obrysu w punktach. Domyślnie 1.0. Może być animowany.
  • lineCap — styl zakończenia linii: .butt (proste cięcie), .round (zaokrąglony), .square (prostokątny z wysunięciem).
  • lineJoin — styl łączenia linii: .miter (ostry kąt), .round (zaokrąglony), .bevel (ścięty).
  • strokeStart i strokeEnd — udział narysowanego konturu od 0.0 do 1.0. Animacja strokeEnd tworzy efekt stopniowego pojawiania się.
  • fillRule — reguła wypełniania przecinających się konturów: .nonZero (domyślnie) lub .evenOdd.
  • miterLimit — maksymalna długość ostrza przy lineJoin = .miter. Zapobiega nieskończenie długim kątom.

Właściwość lineDashPattern pozwala tworzyć linie przerywane. Przyjmuje tablicę liczb: [6, 3] oznacza 6 punktów kreski i 3 punkty przerwy. lineDashPhase określa przesunięcie wzoru i może być animowany dla efektu poruszającej się linii przerywanej.

CAShapeLayer vs CALayer: kiedy wybrać który

Wybór między CAShapeLayer a podstawowym CALayer zależy od typu treści. Jeśli element to prostokątny obszar z tłem, granicą i cieniem — wystarczy CALayer. Jeśli element ma dowolny kształt, wymaga animacji konturu lub skalowania bez utraty jakości — CAShapeLayer jest preferowany.

Wydajność również się różni. CALayer z cornerRadius i masksToBounds tworzy bufor offscreen do przycinania zawartości, co dodaje 2–5 ms na klatkę. CAShapeLayer nie wymaga bufora offscreen — przycinanie odbywa się na poziomie shadera wierzchołków. Dla elementów ze złożoną maską CAShapeLayer może być 2–3 razy szybszy.

  • CALayer: elementy prostokątne, zdjęcia, wideo, treści z zaokrąglonymi rogami (cornerRadius), cienie, granice.
  • CAShapeLayer: ikony, wykresy, paski postępu, maski o dowolnym kształcie, animowane kontury, kształty do animacji pojawiania się.
  • CATextLayer: tekst wymagający subpikselowego renderowania i buforowania glifów.
  • CAGradientLayer: wypełnienia gradientowe — łączony z CAShapeLayer przez mask do tworzenia kształtów z gradientem.

Łączenie CAShapeLayer z innymi warstwami to powszechny wzorzec. Na przykład CAGradientLayer używa CAShapeLayer jako maski do tworzenia kształtu z wypełnieniem gradientowym. Takie podejście daje zarówno jakość wektorową, jak i wypełnienie gradientowe bez utraty wydajności.

Animacja CAShapeLayer: path i stroke

Animacja path — jedna z najpotężniejszych możliwości CAShapeLayer. Jeśli oba kontury (początkowy i końcowy) mają tę samą liczbę punktów kontrolnych i segmentów, Core Animation wykonuje płynną interpolację między nimi. Rezultat — efekt morfingu jednego kształtu w drugi.

Warunek zgodności path: początkowy i końcowy UIBezierPath muszą mieć tę samą strukturę — liczba wywołań moveTo, addLine, addCurve i addQuadCurve musi się zgadzać. Jeśli struktura się różni, animacja będzie natychmiastowa, bez interpolacji.

Według Apple WWDC 2024, kombinacja strokeStart i strokeEnd to najczęściej używany wzorzec animacji CAShapeLayer. Animacja strokeEnd od 0.0 do 1.0 tworzy efekt rysowania konturu od początku do końca. Jest używany we wskaźnikach ładowania, animacjach pojawiania się wykresów i niestandardowych przejściach między ekranami.

Aby stworzyć efekt pulsowania, animuj jednocześnie strokeEnd i opacity z różnymi funkcjami timingowymi. Dla efektu biegnącej linii przerywanej animuj lineDashPhase przy stałym lineDashPattern. Oba triki są realizowane przez CABasicAnimation bez udziału CPU.

Animacja jako maska

CAShapeLayer jest często używany jako mask dla innych warstw. Na przykład do animacji pojawiania się treści: na początku mask.path to prostokąt o zerowym rozmiarze, końcowy — pełny rozmiar. Core Animation interpoluje path, a treść odkrywa się płynnie.

Ten wzorzec jest używany w iOS do animacji rozwijania kart, pojawiania się okien modalnych i przejść między view controllerami. W przeciwieństwie do animacji alpha, animacja przez maskę CAShapeLayer daje bardziej naturalny efekt pojawiania się z dowolnym kształtem.

Przykłady kodu z CAShapeLayer w Swift

Pierwszy przykład — tworzenie okrągłego wskaźnika postępu z animacją strokeEnd. To standardowy element UI, który demonstruje główne możliwości 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
}

// Animacja do 75%
progressLayer.animateStrokeEnd(to: 0.75, duration: 1.5)

Drugi przykład — animacja morfingu między kołem a kwadratem. Oba UIBezierPath mają zgodną strukturę:

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

Trzeci przykład — maska z CAShapeLayer do animacji pojawiania się treści. Maska rozszerza się od środka do krawędzi:

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
}

Często zadawane pytania

Czym się różni CAShapeLayer od rysowania w drawRect?

drawRect używa CPU do renderowania w kontekście rastrowym — jest wolne dla animacji. CAShapeLayer renderuje kontur na GPU, co daje 60 FPS przy animacji path, strokeEnd i transformacji. Ponadto CAShapeLayer nie wymaga przerysowania przy zmianie rozmiarów — kształt skaluje się wektorowo.

Dlaczego animacja path nie działa płynnie?

Płynna animacja path wymaga jednakowej struktury początkowego i końcowego UIBezierPath. Liczba wywołań moveTo, addLine, addCurve musi się zgadzać. Używaj UIBezierPath z tą samą liczbą segmentów dla kształtu początkowego i końcowego.

Jak utworzyć linię przerywaną w CAShapeLayer?

Ustaw lineDashPattern — tablicę liczb naprzemiennie określających długość kreski i przerwy. Na przykład [8, 4] tworzy kreski 8pt z przerwami 4pt. Dla biegnącej linii przerywanej animuj lineDashPhase przez CABasicAnimation z liniową funkcją timingową.

Czy można użyć CAShapeLayer jako maski?

Tak, to jeden z głównych scenariuszy. Przypisz CAShapeLayer do właściwości mask dowolnego CALayer, w tym CAGradientLayer i innych podklas. Animacja path maski tworzy efekt płynnego pojawiania się treści przez kształt o dowolnej formie.

Jak wypełnić kształt gradientem przez CAShapeLayer?

Utwórz CAGradientLayer i ustaw jego mask = CAShapeLayer z odpowiednim path. Gradient będzie widoczny tylko wewnątrz konturu maski. Ten wzorzec łączy zalety wektorowego kształtu CAShapeLayer z wypełnieniem gradientowym CAGradientLayer.

Podsumowanie

  • CAShapeLayer — podklasa CALayer do sprzętowego renderowania wektorowych konturów na GPU przez CGPath.
  • Kluczowe właściwości: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, strokeStart, strokeEnd.
  • Animacja path tworzy morfing kształtów — wymaga jednakowej struktury początkowego i końcowego konturu.
  • Animacja strokeEnd — standardowy wzorzec dla wskaźników postępu i rysowania konturów.
  • CAShapeLayer nie wymaga bufora offscreen do maskowania, w przeciwieństwie do CALayer z masksToBounds.
  • Używany jako maska dla CAGradientLayer, tworząc kształty z wypełnieniem gradientowym.
  • Dla linii przerywanych używaj lineDashPattern z animacją lineDashPhase dla efektu ruchu.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również