CAShapeLayer — какво е това, свойства и създаване на фигури

Автор: IT Sectr Публикувано: 2026-06-12 Време за четене: 10 мин

CAShapeLayer — е подклас на CALayer, предназначен за хардуерно изобразяване на векторни контури на GPU. За разлика от основния CALayer, който работи с растерни изображения чрез contents, CAShapeLayer изобразява произволни фигури, зададени чрез CGPath, без създаване на отделен offscreen буфер. Според Apple QuartzCore Documentation, 2025, CAShapeLayer използва хардуерно ускорение за изглаждане на ръбове и поддържа анимация на path, strokeStart и strokeEnd. Това е стандартният инструмент за създаване на икони, индикатори за напредък и маски в iOS.

Основни точки

  • CAShapeLayer — подклас на CALayer за изобразяване на векторни фигури на GPU чрез CGPath.
  • Изобразяването на контур се извършва хардуерно без създаване на междинен растерен буфер — това е по-бързо от Core Graphics.
  • Свойства fillColor, strokeColor, lineWidth, lineCap, lineJoin управляват външния вид на фигурата.
  • Анимация на path позволява плавно преобразуване на една фигура в друга — ключова възможност за UI анимации.
  • strokeStart и strokeEnd се анимират за създаване на ефект на рисуване на контур — идеално за индикатори за зареждане.

Какво е CAShapeLayer?

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 е особено полезен за елементи на интерфейса, които променят формата си в отговор на действията на потребителя: индикатори за напредък, графики, икони на таб-бар, маски за анимация на появяване на съдържание.

Как CAShapeLayer изобразява контур на GPU

Процесът на изобразяване на CAShapeLayer се различава от основния CALayer. Вместо да съхранява растерен буфер с пиксели, CAShapeLayer изпраща на GPU описанието на върховете на контура — набор от точки, криви на Безие и сегменти. GPU растеризира този контур за едно преминаване, прилагайки цвят на запълване и контур на етапа на фрагментния шейдър.

Този подход дава две предимства: мащабиране без загуба на качество (векторната графика остава ясна при всяка разделителна способност) и ефективна анимация — при промяна на path GPU преизчислява само променените пиксели, а не целия екран.

Основни свойства на CAShapeLayer

path — централното свойство на CAShapeLayer, приемащо CGPath. Контурът може да съдържа линии, дъги, криви на Безие и правоъгълници. Създава се чрез UIBezierPath в Swift или CGPath в Core Graphics. Пример: UIBezierPath(roundedRect: rect, cornerRadius: 16).cgPath създава заоблен правоъгълник.

  • fillColor — цвят на запълване на затворен контур (CGColor). Ако е nil — без запълване. Поддържа анимация.
  • strokeColor — цвят на контура. Анимира се заедно с lineWidth, създавайки ефект на рисуващ се контур.
  • lineWidth — дебелина на линията на контура в точки. По подразбиране 1.0. Може да се анимира.
  • lineCap — стил на завършек на линия: .butt (прав срез), .round (заоблен), .square (правоъгълен с издатина).
  • lineJoin — стил на свързване на линии: .miter (остър ъгъл), .round (заоблен), .bevel (отрязан).
  • strokeStart и strokeEnd — дял на нарисувания контур от 0.0 до 1.0. Анимацията на strokeEnd създава ефект на постепенно появяване.
  • fillRule — правило за запълване на пресичащи се контури: .nonZero (по подразбиране) или .evenOdd.
  • miterLimit — максимална дължина на върха при lineJoin = .miter. Предотвратява безкрайно дълги ъгли.

Свойството lineDashPattern позволява създаване на пунктирани линии. Приема масив от числа: [6, 3] означава 6 точки линия и 3 точки интервал. lineDashPhase задава отместване на модела и може да се анимира за ефект на движеща се пунктирана линия.

CAShapeLayer срещу CALayer: кога да изберем кой

Изборът между CAShapeLayer и основния CALayer зависи от типа съдържание. Ако елементът е правоъгълна област с фон, граница и сянка — достатъчен е CALayer. Ако елементът има произволна форма, изисква анимация на контура или мащабиране без загуба на качество — CAShapeLayer е за предпочитане.

Производителността също се различава. CALayer с cornerRadius и masksToBounds създава offscreen буфер за изрязване на съдържание, което добавя 2–5 ms на кадър. CAShapeLayer не изисква offscreen буфер — изрязването става на ниво vertex шейдър. За елементи със сложна маска, CAShapeLayer може да бъде 2–3 пъти по-бърз.

  • CALayer: правоъгълни елементи, снимки, видео, съдържание със заоблени ъгли (cornerRadius), сенки, граници.
  • CAShapeLayer: икони, графики, ленти за напредък, маски с произволна форма, анимирани контури, фигури за анимация на появяване.
  • CATextLayer: текст, изискващ субпикселно изобразяване и кеширане на глифове.
  • CAGradientLayer: градиентни запълвания — комбинира се с CAShapeLayer чрез mask за създаване на фигури с градиент.

Комбинирането на CAShapeLayer с други слоеве е често срещан модел. Например CAGradientLayer използва CAShapeLayer като маска за създаване на фигура с градиентно запълване. Този подход дава както векторно качество, така и градиентно запълване без загуба на производителност.

Анимация на CAShapeLayer: path и stroke

Анимация на 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 дава по-естествен ефект на появяване с произволна форма.

Примери за код с CAShapeLayer в Swift

Първи пример — създаване на кръгъл индикатор за напредък с анимация на strokeEnd. Това е стандартен UI елемент, който демонстрира основните възможности на 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
}

// Анимиране до 75%
progressLayer.animateStrokeEnd(to: 0.75, duration: 1.5)

Втори пример — анимация на трансформиране между кръг и квадрат. И двата UIBezierPath имат съвместима структура:

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

Трети пример — маска с CAShapeLayer за анимация на появяване на съдържание. Маската се разширява от центъра към краищата:

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
}

Често задавани въпроси

Как се различава CAShapeLayer от рисуването в drawRect?

drawRect използва CPU за изобразяване в растерен контекст — това е бавно за анимации. CAShapeLayer изобразява контура на GPU, което дава 60 FPS при анимация на path, strokeEnd и трансформации. Освен това CAShapeLayer не изисква преизобразяване при промяна на размерите — фигурата се мащабира векторно.

Защо анимацията на path не работи плавно?

Плавната анимация на path изисква еднаква структура на началния и крайния UIBezierPath. Броят на извикванията на moveTo, addLine, addCurve трябва да съвпада. Използвайте UIBezierPath с еднакъв брой сегменти за началната и крайната фигура.

Как да създадем пунктирана линия в CAShapeLayer?

Задайте lineDashPattern — масив от числа, които последователно определят дължината на чертата и интервала. Например [8, 4] създава черти от 8pt с интервали от 4pt. За движеща се пунктирана линия, анимирайте lineDashPhase чрез CABasicAnimation с линейна функция на времето.

Може ли CAShapeLayer да се използва като маска?

Да, това е един от основните сценарии. Присвоете CAShapeLayer на свойството mask на произволен CALayer, включително CAGradientLayer и други подкласове. Анимацията на path на маската създава ефект на плавно появяване на съдържание чрез фигура с произволна форма.

Как да запълним фигура с градиент чрез CAShapeLayer?

Създайте CAGradientLayer и задайте неговия mask = CAShapeLayer с желания path. Градиентът ще бъде видим само вътре в контура на маската. Този модел съчетава предимствата на векторната форма на CAShapeLayer с градиентното запълване на CAGradientLayer.

Резюме

  • CAShapeLayer — подклас на CALayer за хардуерно изобразяване на векторни контури на GPU чрез CGPath.
  • Ключови свойства: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, strokeStart, strokeEnd.
  • Анимацията на path създава трансформиране на фигури — изисква еднаква структура на началния и крайния контур.
  • Анимацията на strokeEnd — стандартен модел за индикатори за напредък и рисуване на контури.
  • CAShapeLayer не изисква offscreen буфер за маскиране, за разлика от CALayer с masksToBounds.
  • Използва се като маска за CAGradientLayer, създавайки фигури с градиентно запълване.
  • За пунктирани линии използвайте lineDashPattern с анимация на lineDashPhase за ефект на движение.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също