CAShapeLayer — ce que c'est, propriétés et création de formes

Auteur : IT Sectr Publié le : 2026-06-12 Temps de lecture : 10 min

CAShapeLayer est une sous-classe de CALayer conçue pour le rendu accéléré par matériel de tracés vectoriels sur le GPU. Contrairement à CALayer de base, qui travaille avec des images raster via contents, CAShapeLayer rend des formes arbitraires définies via CGPath sans créer de buffer hors écran séparé. Selon Apple QuartzCore Documentation, 2025, CAShapeLayer utilise l'accélération matérielle pour l'anticrénelage des bords et prend en charge l'animation de path, strokeStart et strokeEnd. C'est un outil standard pour créer des icônes, des indicateurs de progression et des masques dans iOS.

Points Clés

  • CAShapeLayer — une sous-classe de CALayer pour le rendu de formes vectorielles sur le GPU via CGPath.
  • Le rendu du tracé est effectué par matériel sans créer de buffer raster intermédiaire — c'est plus rapide que Core Graphics.
  • Les propriétés fillColor, strokeColor, lineWidth, lineCap, lineJoin contrôlent l'apparence de la forme.
  • L'animation de path permet de transformer en douceur une forme en une autre — une capacité clé pour les animations d'interface.
  • strokeStart et strokeEnd sont animés pour créer un effet de dessin du tracé — idéal pour les indicateurs de chargement.

Qu'est-ce que CAShapeLayer ?

CAShapeLayer est une couche spécialisée pour le rendu de graphiques vectoriels, introduite dans iOS 3.0. Contrairement à CALayer, qui stocke une image raster, CAShapeLayer stocke une description mathématique d'un tracé — CGPath — et le rend directement sur le GPU. Cela permet de mettre à l'échelle la forme sans perte de qualité et d'animer ses propriétés sans redessiner le contenu.

Architecturalement, CAShapeLayer hérite de toutes les capacités de CALayer : ombres, bordures, transformations, masques. Mais il ajoute des propriétés spécifiques pour travailler avec les tracés : path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, miterLimit, strokeStart, strokeEnd et fillRule. Chacune de ces propriétés peut être animée via CABasicAnimation.

Selon Apple Documentation, CAShapeLayer utilise l'accélération matérielle pour le rendu. Contrairement au dessin via Core Graphics dans drawRect:, où le CPU rend le tracé dans un contexte raster, CAShapeLayer envoie des commandes directement au GPU via Metal. Le résultat est des performances plus élevées, surtout pendant l'animation.

CAShapeLayer est particulièrement utile pour les éléments d'interface qui changent de forme en réponse aux actions de l'utilisateur : indicateurs de progression, graphiques, icônes de barre d'onglets, masques pour les animations de révélation de contenu.

Comment CAShapeLayer rend un tracé sur le GPU

Le processus de rendu de CAShapeLayer diffère de celui de CALayer de base. Au lieu de stocker un buffer raster avec des pixels, CAShapeLayer transmet une description de sommets du tracé au GPU — un ensemble de points, de courbes de Bézier et de segments de ligne. Le GPU rasterise ce tracé en une seule passe, appliquant les couleurs de remplissage et de trait au niveau du shader de fragments.

Cette approche offre deux avantages : la mise à l'échelle sans perte de qualité (les graphiques vectoriels restent nets à n'importe quelle résolution) et une animation efficace — lorsque le tracé change, le GPU ne recalcule que les pixels modifiés, pas tout l'écran.

Principales propriétés de CAShapeLayer

path — la propriété centrale de CAShapeLayer, qui accepte un CGPath. Le tracé peut contenir des lignes, des arcs, des courbes de Bézier et des rectangles. Il est créé via UIBezierPath en Swift ou CGPath dans Core Graphics. Exemple : UIBezierPath(roundedRect: rect, cornerRadius: 16).cgPath crée un rectangle arrondi.

  • fillColor — la couleur de remplissage du tracé fermé (CGColor). Si nil, pas de remplissage. Prend en charge l'animation.
  • strokeColor — la couleur de trait du tracé. S'anime avec lineWidth, créant un effet de dessin du tracé.
  • lineWidth — l'épaisseur de la ligne de trait en points. Par défaut 1.0. Peut être animé.
  • lineCap — le style d'extrémité de ligne : .butt (coupe droite), .round (arrondi), .square (rectangulaire avec saillie).
  • lineJoin — le style de jonction de lignes : .miter (angle aigu), .round (arrondi), .bevel (biseauté).
  • strokeStart et strokeEnd — la fraction du tracé dessiné de 0.0 à 1.0. Animer strokeEnd crée un effet de révélation progressive.
  • fillRule — la règle de remplissage pour les tracés qui se croisent : .nonZero (par défaut) ou .evenOdd.
  • miterLimit — la longueur maximale de l'angle lorsque lineJoin = .miter. Empêche les coins infiniment longs.

La propriété lineDashPattern permet de créer des lignes pointillées. Elle accepte un tableau de nombres : [6, 3] signifie 6 points de trait et 3 points d'espace. lineDashPhase définit le décalage du motif et peut être animé pour un effet de pointillé mobile.

CAShapeLayer vs CALayer : quand choisir chacun

Le choix entre CAShapeLayer et CALayer de base dépend du type de contenu. Si l'élément est une zone rectangulaire avec fond, bordure et ombre — CALayer suffit. Si l'élément a une forme arbitraire, nécessite une animation de tracé ou une mise à l'échelle sans perte de qualité — CAShapeLayer est préférable.

Les performances diffèrent également. CALayer avec cornerRadius et masksToBounds crée un buffer hors écran pour le clipping du contenu, ajoutant 2–5 ms par image. CAShapeLayer ne nécessite pas de buffer hors écran — le clipping est effectué au niveau du shader de sommets. Pour les éléments avec des masques complexes, CAShapeLayer peut être 2 à 3 fois plus rapide.

  • CALayer : éléments rectangulaires, photos, vidéo, contenu avec coins arrondis (cornerRadius), ombres, bordures.
  • CAShapeLayer : icônes, graphiques, barres de progression, masques de forme arbitraire, tracés animés, formes pour animations de révélation.
  • CATextLayer : texte nécessitant un rendu sous-pixel et une mise en cache des glyphes.
  • CAGradientLayer : remplissages dégradés — combiné avec CAShapeLayer via mask pour créer des formes avec dégradé.

Combiner CAShapeLayer avec d'autres couches est un motif courant. Par exemple, CAGradientLayer utilise CAShapeLayer comme masque pour créer une forme avec un remplissage dégradé. Cette approche offre à la fois la qualité vectorielle et le remplissage dégradé sans perte de performances.

Animation de CAShapeLayer : path et stroke

L'animation de path est l'une des fonctionnalités les plus puissantes de CAShapeLayer. Si les deux tracés (initial et final) ont le même nombre de points de contrôle et de segments, Core Animation effectue une interpolation fluide entre eux. Le résultat est un effet de morphing d'une forme à une autre.

Condition de compatibilité du tracé : l'UIBezierPath initial et final doivent avoir la même structure — le nombre d'appels moveTo, addLine, addCurve et addQuadCurve doit correspondre. Si la structure diffère, l'animation sera instantanée, sans interpolation.

Selon Apple WWDC 2024, la combinaison de strokeStart et strokeEnd est le motif d'animation CAShapeLayer le plus utilisé. Animer strokeEnd de 0.0 à 1.0 crée un effet de dessin du tracé du début à la fin. Cela est utilisé dans les indicateurs de chargement, les animations de révélation de graphiques et les transitions d'écran personnalisées.

Pour créer un effet de pulsation, animez strokeEnd et opacity simultanément avec différentes fonctions de synchronisation. Pour un effet de fourmis marchantes, animez lineDashPhase avec un lineDashPattern fixe. Les deux techniques sont implémentées via CABasicAnimation sans implication du CPU.

Animation en tant que masque

CAShapeLayer est souvent utilisé comme masque pour d'autres couches. Par exemple, pour l'animation de révélation de contenu : initialement, mask.path est un rectangle de taille zéro, et le final est de taille réelle. Core Animation interpole le tracé et le contenu apparaît en douceur.

Ce motif est utilisé dans iOS pour l'animation d'expansion de cartes, la présentation de fenêtres modales et les transitions entre contrôleurs de vue. Contrairement à l'animation alpha, l'animation de masque CAShapeLayer offre un effet de révélation plus naturel avec des formes arbitraires.

Exemples de code avec CAShapeLayer en Swift

Le premier exemple — création d'un indicateur de progression circulaire avec animation strokeEnd. C'est un élément d'interface standard qui démontre les capacités principales de 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
}

// Animer à 75%
progressLayer.animateStrokeEnd(to: 0.75, duration: 1.5)

Le deuxième exemple — animation de morphing entre un cercle et un carré. Les deux UIBezierPath ont une structure compatible :

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

Le troisième exemple — un masque CAShapeLayer pour l'animation de révélation de contenu. Le masque s'étend du centre vers les bords :

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
}

Questions Fréquemment Posées

En quoi CAShapeLayer diffère-t-il du dessin dans drawRect ?

drawRect utilise le CPU pour rendre dans un contexte raster — c'est lent pour les animations. CAShapeLayer rend le tracé sur le GPU, offrant 60 FPS lors des animations de path, strokeEnd et des transformations. De plus, CAShapeLayer ne nécessite pas de redessin lors du redimensionnement — la forme est mise à l'échelle vectoriellement.

Pourquoi l'animation de path ne fonctionne-t-elle pas correctement ?

Une animation fluide du tracé nécessite une structure identique de l'UIBezierPath initial et final. Le nombre d'appels moveTo, addLine, addCurve doit correspondre. Utilisez UIBezierPath avec le même nombre de segments pour les formes initiale et finale.

Comment créer une ligne pointillée dans CAShapeLayer ?

Définissez lineDashPattern — un tableau de nombres alternant les longueurs de trait et d'espace. Par exemple, [8, 4] crée des traits de 8pt avec des espaces de 4pt. Pour un effet de fourmis marchantes, animez lineDashPhase via CABasicAnimation avec une fonction de synchronisation linéaire.

CAShapeLayer peut-il être utilisé comme masque ?

Oui, c'est l'un des principaux cas d'utilisation. Assignez CAShapeLayer à la propriété mask de n'importe quel CALayer, y compris CAGradientLayer et d'autres sous-classes. Animer le tracé du masque crée un effet de révélation fluide du contenu à travers une forme arbitraire.

Comment remplir une forme avec un dégradé via CAShapeLayer ?

Créez un CAGradientLayer et définissez son mask = CAShapeLayer avec le tracé souhaité. Le dégradé ne sera visible qu'à l'intérieur du tracé du masque. Ce motif combine les avantages de la forme vectorielle de CAShapeLayer et le remplissage dégradé de CAGradientLayer.

Résumé

  • CAShapeLayer — une sous-classe de CALayer pour le rendu accéléré par matériel de tracés vectoriels sur le GPU via CGPath.
  • Propriétés clés : path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, strokeStart, strokeEnd.
  • L'animation de path crée un morphing de formes — nécessite une structure identique des tracés initial et final.
  • L'animation de strokeEnd — un motif standard pour les indicateurs de progression et le dessin de tracés.
  • CAShapeLayer ne nécessite pas de buffer hors écran pour le masquage, contrairement à CALayer avec masksToBounds.
  • Utilisé comme masque pour CAGradientLayer, créant des formes avec un remplissage dégradé.
  • Pour les lignes pointillées, utilisez lineDashPattern avec l'animation lineDashPhase pour un effet de mouvement.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi