CAShapeLayer — o que é, propriedades e criação de formas

Autor: IT Sectr Publicado: 2026-06-12 Tempo de leitura: 10 min

CAShapeLayer é uma subclasse de CALayer projetada para renderização acelerada por hardware de traçados vetoriais na GPU. Ao contrário do CALayer básico, que trabalha com imagens raster através de contents, o CAShapeLayer renderiza formas arbitrárias definidas através de CGPath sem criar um buffer offscreen separado. De acordo com Apple QuartzCore Documentation, 2025, o CAShapeLayer usa aceleração de hardware para suavização de bordas e suporta animação de path, strokeStart e strokeEnd. É uma ferramenta padrão para criar ícones, indicadores de progresso e máscaras no iOS.

Pontos Principais

  • CAShapeLayer — uma subclasse de CALayer para renderizar formas vetoriais na GPU via CGPath.
  • A renderização do traçado é feita por hardware sem criar um buffer raster intermediário — é mais rápido que Core Graphics.
  • Propriedades fillColor, strokeColor, lineWidth, lineCap, lineJoin controlam a aparência da forma.
  • A animação de path permite transformar suavemente uma forma em outra — uma capacidade chave para animações de UI.
  • strokeStart e strokeEnd são animados para criar um efeito de desenho do traçado — ideal para indicadores de carregamento.

O que é CAShapeLayer?

CAShapeLayer é uma camada especializada para renderizar gráficos vetoriais, introduzida no iOS 3.0. Ao contrário do CALayer, que armazena uma imagem raster, o CAShapeLayer armazena uma descrição matemática de um traçado — CGPath — e o renderiza diretamente na GPU. Isso permite escalar a forma sem perda de qualidade e animar suas propriedades sem redesenhar o conteúdo.

Arquiteturalmente, o CAShapeLayer herda todas as capacidades do CALayer: sombras, bordas, transformações, máscaras. Mas adiciona propriedades específicas para trabalhar com traçados: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, miterLimit, strokeStart, strokeEnd e fillRule. Cada uma dessas propriedades pode ser animada através de CABasicAnimation.

De acordo com Apple Documentation, o CAShapeLayer usa aceleração de hardware para renderização. Ao contrário do desenho via Core Graphics em drawRect:, onde a CPU renderiza o traçado em um contexto raster, o CAShapeLayer envia comandos diretamente para a GPU via Metal. O resultado é maior desempenho, especialmente durante a animação.

O CAShapeLayer é particularmente útil para elementos de interface que mudam de forma em resposta a ações do usuário: indicadores de progresso, gráficos, ícones de barra de abas, máscaras para animações de revelação de conteúdo.

Como o CAShapeLayer renderiza um traçado na GPU

O processo de renderização do CAShapeLayer difere do CALayer básico. Em vez de armazenar um buffer raster com pixels, o CAShapeLayer passa uma descrição de vértices do traçado para a GPU — um conjunto de pontos, curvas Bezier e segmentos de linha. A GPU rasteriza este traçado em uma única passada, aplicando cores de preenchimento e traço no estágio do shader de fragmentos.

Esta abordagem oferece duas vantagens: escalonamento sem perda de qualidade (gráficos vetoriais permanecem nítidos em qualquer resolução) e animação eficiente — quando o traçado muda, a GPU recalcula apenas os pixels alterados, não a tela inteira.

Propriedades principais do CAShapeLayer

path — a propriedade central do CAShapeLayer, que aceita um CGPath. O traçado pode conter linhas, arcos, curvas Bezier e retângulos. É criado através de UIBezierPath em Swift ou CGPath em Core Graphics. Exemplo: UIBezierPath(roundedRect: rect, cornerRadius: 16).cgPath cria um retângulo arredondado.

  • fillColor — a cor de preenchimento do traçado fechado (CGColor). Se for nil, sem preenchimento. Suporta animação.
  • strokeColor — a cor do traço do traçado. Anima junto com lineWidth, criando um efeito de desenho do traçado.
  • lineWidth — a espessura da linha do traço em pontos. O padrão é 1.0. Pode ser animado.
  • lineCap — o estilo da extremidade da linha: .butt (corte reto), .round (arredondado), .square (retangular com saliência).
  • lineJoin — o estilo de união de linhas: .miter (ângulo agudo), .round (arredondado), .bevel (chanfrado).
  • strokeStart e strokeEnd — a fração do traçado desenhado de 0.0 a 1.0. Animar strokeEnd cria um efeito de revelação gradual.
  • fillRule — a regra de preenchimento para traçados que se cruzam: .nonZero (padrão) ou .evenOdd.
  • miterLimit — o comprimento máximo do ângulo quando lineJoin = .miter. Previne cantos infinitamente longos.

A propriedade lineDashPattern permite criar linhas tracejadas. Aceita um array de números: [6, 3] significa 6 pontos de traço e 3 pontos de espaço. lineDashPhase define o deslocamento do padrão e pode ser animado para um efeito de traço em movimento.

CAShapeLayer vs CALayer: quando escolher cada um

A escolha entre CAShapeLayer e o CALayer básico depende do tipo de conteúdo. Se o elemento é uma área retangular com fundo, borda e sombra — CALayer é suficiente. Se o elemento tem uma forma arbitrária, requer animação do traçado ou escalonamento sem perda de qualidade — CAShapeLayer é preferível.

O desempenho também difere. CALayer com cornerRadius e masksToBounds cria um buffer offscreen para recortar conteúdo, adicionando 2–5 ms por quadro. CAShapeLayer não requer buffer offscreen — o recorte é feito no nível do shader de vértices. Para elementos com máscaras complexas, CAShapeLayer pode ser 2–3 vezes mais rápido.

  • CALayer: elementos retangulares, fotos, vídeo, conteúdo com cantos arredondados (cornerRadius), sombras, bordas.
  • CAShapeLayer: ícones, gráficos, barras de progresso, máscaras de forma arbitrária, traçados animados, formas para animações de revelação.
  • CATextLayer: texto que requer renderização subpixel e cache de glifos.
  • CAGradientLayer: preenchimentos gradientes — combinado com CAShapeLayer através de mask para criar formas com gradiente.

Combinar CAShapeLayer com outras camadas é um padrão comum. Por exemplo, CAGradientLayer usa CAShapeLayer como máscara para criar uma forma com preenchimento gradiente. Esta abordagem fornece qualidade vetorial e preenchimento gradiente sem perda de desempenho.

Animação do CAShapeLayer: path e stroke

A animação de path é um dos recursos mais poderosos do CAShapeLayer. Se ambos os traçados (inicial e final) tiverem o mesmo número de pontos de controle e segmentos, o Core Animation realiza uma interpolação suave entre eles. O resultado é um efeito de transformação de uma forma em outra.

Condição de compatibilidade do traçado: o UIBezierPath inicial e final devem ter a mesma estrutura — o número de chamadas moveTo, addLine, addCurve e addQuadCurve deve coincidir. Se a estrutura diferir, a animação será instantânea, sem interpolação.

De acordo com Apple WWDC 2024, a combinação de strokeStart e strokeEnd é o padrão de animação CAShapeLayer mais usado. Animar strokeEnd de 0.0 a 1.0 cria um efeito de desenho do traçado do início ao fim. Isso é usado em indicadores de carregamento, animações de revelação de gráficos e transições personalizadas entre telas.

Para criar um efeito pulsante, anime strokeEnd e opacity simultaneamente com diferentes funções de temporização. Para um efeito de formigas marchando, anime lineDashPhase com um lineDashPattern fixo. Ambas as técnicas são implementadas via CABasicAnimation sem envolvimento da CPU.

Animação como máscara

CAShapeLayer é frequentemente usado como máscara para outras camadas. Por exemplo, para animação de revelação de conteúdo: inicialmente, mask.path é um retângulo de tamanho zero, e o final é de tamanho completo. O Core Animation interpola o traçado e o conteúdo é revelado suavemente.

Este padrão é usado no iOS para animação de expansão de cartões, apresentação de janelas modais e transições entre controladores de vista. Ao contrário da animação alpha, a animação de máscara CAShapeLayer fornece um efeito de revelação mais natural com formas arbitrárias.

Exemplos de código com CAShapeLayer em Swift

O primeiro exemplo — criação de um indicador de progresso circular com animação strokeEnd. Este é um elemento de UI padrão que demonstra as capacidades principais do 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
}

// Animar para 75%
progressLayer.animateStrokeEnd(to: 0.75, duration: 1.5)

O segundo exemplo — animação de transformação entre um círculo e um quadrado. Ambos UIBezierPath têm uma estrutura compatível:

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

O terceiro exemplo — uma máscara CAShapeLayer para animação de revelação de conteúdo. A máscara expande do centro para as bordas:

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
}

Perguntas Frequentes

Como o CAShapeLayer difere de desenhar em drawRect?

drawRect usa a CPU para renderizar em um contexto raster — isso é lento para animações. CAShapeLayer renderiza o traçado na GPU, oferecendo 60 FPS durante animações de path, strokeEnd e transformações. Além disso, CAShapeLayer não requer redesenho ao redimensionar — a forma escala vetorialmente.

Por que a animação de path não funciona suavemente?

A animação suave do traçado requer estrutura idêntica do UIBezierPath inicial e final. O número de chamadas moveTo, addLine, addCurve deve coincidir. Use UIBezierPath com o mesmo número de segmentos para as formas inicial e final.

Como criar uma linha tracejada no CAShapeLayer?

Defina lineDashPattern — um array de números alternando comprimentos de traço e espaço. Por exemplo, [8, 4] cria traços de 8pt com espaços de 4pt. Para um efeito de formigas marchando, anime lineDashPhase via CABasicAnimation com uma função de temporização linear.

CAShapeLayer pode ser usado como máscara?

Sim, este é um dos principais casos de uso. Atribua CAShapeLayer à propriedade mask de qualquer CALayer, incluindo CAGradientLayer e outras subclasses. Animar o traçado da máscara cria um efeito de revelação suave do conteúdo através de uma forma arbitrária.

Como preencher uma forma com gradiente via CAShapeLayer?

Crie um CAGradientLayer e defina seu mask = CAShapeLayer com o traçado desejado. O gradiente será visível apenas dentro do traçado da máscara. Este padrão combina as vantagens de forma vetorial do CAShapeLayer e o preenchimento gradiente do CAGradientLayer.

Resumo

  • CAShapeLayer — uma subclasse de CALayer para renderização acelerada por hardware de traçados vetoriais na GPU via CGPath.
  • Propriedades principais: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, strokeStart, strokeEnd.
  • A animação de path cria transformação de formas — requer estrutura idêntica dos traçados inicial e final.
  • A animação de strokeEnd — um padrão padrão para indicadores de progresso e desenho de traçados.
  • CAShapeLayer não requer buffer offscreen para mascaramento, ao contrário de CALayer com masksToBounds.
  • Usado como máscara para CAGradientLayer, criando formas com preenchimento gradiente.
  • Para linhas tracejadas, use lineDashPattern com animação lineDashPhase para um efeito de movimento.

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também