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 vs CALayer: когда выбирать каждый

Выбор между CAShapeLayer и базовым CALayer зависит от типа контента. Если элемент — прямоугольная область с фоном, границей и тенью — достаточно CALayer. Если элемент имеет произвольную форму, требует анимации контура или масштабирования без потери качества — CAShapeLayer предпочтительнее.

Производительность также различается. CALayer с cornerRadius и masksToBounds создаёт offscreen-буфер для обрезки содержимого, что добавляет 2–5 мс на кадр. CAShapeLayer не требует offscreen-буфера — обрезка выполняется на уровне вершинного шейдера. Для элементов со сложной маской 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 с разными timing functions. Для эффекта бегущего пунктира анимируйте lineDashPhase при фиксированном lineDashPattern. Оба приёма реализуются через CABasicAnimation без участия CPU.

Анимация в качестве маски

CAShapeLayer часто используется как mask для других слоёв. Например, для анимации появления контента: на начальном этапе mask.path — это прямоугольник нулевого размера, конечный — полный размер. Core Animation интерполирует path, и контент открывается плавно.

Этот паттерн используется в iOS для анимации разворачивания карточек, появления модальных окон и transition между view controllers. В отличие от анимации 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
}

// Animate to 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 с линейной timing function.

Можно ли использовать 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 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также