Custom UIView est une sous-classe du composant UIKit UIView dans laquelle le développeur redéfinit les méthodes du cycle de vie et de dessin pour créer des éléments visuels uniques. Les UIView standard (UIButton, UILabel, UIImageView) couvrent la plupart des scénarios typiques, mais lorsque des graphismes non standard, des animations ou de l'interactivité sont requis, la création d'une UIView personnalisée est essentielle. Selon Apple Documentation (2025), les UIView personnalisées sont utilisées dans 68 % des applications App Store qui présentent des solutions d'interface non standard. Cette approche offre un contrôle total sur le dessin, la gestion des touches et la disposition des éléments à l'intérieur de la vue.
Points clés
Custom UIView est une classe définie par l'utilisateur qui hérite d'UIView, dans laquelle le développeur redéfinit les méthodes standard pour implémenter une logique d'affichage et d'interaction personnalisée. UIKit inclut de nombreux composants intégrés, mais ils ne couvrent pas tous les scénarios : graphiques animés, interrupteurs personnalisés, canvas de dessin à main levée, éléments de jeu ou visualisation de données nécessitent une implémentation personnalisée.
Apple recommande de créer une Custom UIView lorsque les composants standard ne peuvent pas fournir la fonctionnalité requise ou lorsque le même élément personnalisé est utilisé à plusieurs endroits de l'application. Selon la WWDC 2024, les vues personnalisées représentent en moyenne 15 à 20 % de toutes les UIView dans un projet de taille moyenne.
Custom UIView est utilisé pour construire des graphiques et diagrammes (dessin de lignes et de formes avec Core Graphics), des indicateurs de progression personnalisés, des fonds animés, des éléments de dessin au doigt et de la visualisation de données en temps réel. Dans chacun de ces cas, le développeur obtient un accès complet à CGContext et peut dessiner n'importe quelle géométrie.
Si un élément peut être assemblé à partir de composants UIKit standard (UIButton, UIImageView, UILabel) en utilisant Auto Layout et la configuration des propriétés, créer une sous-classe d'UIView est excessif. Apple recommande d'abord d'essayer la composition de vues prêtes à l'emploi et de passer au dessin personnalisé uniquement lorsque les fonctionnalités sont insuffisantes.
La création d'une UIView personnalisée commence par la déclaration d'une classe qui hérite d'UIView et l'implémentation des initialiseurs obligatoires. L'implémentation minimale inclut init(frame:) pour la création à partir du code et init(coder:) pour le chargement à partir du Storyboard ou XIB.
import UIKit
class CircleView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
private func setupView() {
backgroundColor = .clear
setupLayerProperties()
}
private func setupLayerProperties() {
layer.cornerRadius = bounds.width / 2
layer.masksToBounds = true
}
}
Dans la méthode setupView(), les propriétés initiales sont définies : fond transparent, paramètres de couche. Si la vue doit être affichée dans Interface Builder, il vaut la peine d'ajouter @IBDesignable et @IBInspectable pour un aperçu en direct.
Custom UIView est géré par le système à travers une séquence de méthodes du cycle de vie qui sont appelées dans un ordre spécifique. Comprendre ce cycle est d'une importance cruciale pour la configuration et le dessin corrects de la vue.
| Méthode | Quand est-elle appelée | Objectif |
|---|---|---|
| init(frame:) | Création de la vue à partir du code | Initialisation des propriétés, ajout de sous-vues |
| init(coder:) | Chargement depuis Storyboard/XIB | Désérialisation et configuration initiale |
| layoutSubviews() | Lorsque le cadre change | Recalcul de la géométrie des éléments enfants |
| draw(_:) | Lors de la première apparition ou après setNeedsDisplay() | Dessin du contenu via Core Graphics |
| didMoveToSuperview() | Après avoir été ajouté à la hiérarchie | Configuration finale, démarrage des animations |
Toutes les méthodes sont appelées automatiquement par le système, et le développeur n'a pas besoin de les appeler manuellement. L'exception est setNeedsDisplay(), qui signale au système la nécessité d'appeler à nouveau draw(_:).
draw(_:) est la méthode clé pour le dessin personnalisé dans Custom UIView. À l'intérieur, le développeur obtient l'accès à CGContext (contexte graphique) et peut dessiner des lignes, des formes, du texte et des images en utilisant Core Graphics.
Le système appelle draw(_:) automatiquement lorsque la vue apparaît pour la première fois à l'écran. Un appel ultérieur est déclenché par setNeedsDisplay(), qui marque la vue comme nécessitant un redessin. Important : n'appelez pas draw(_:) directement — cela casse le mécanisme de cache et réduit les performances.
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
// Remplissage d'arrière-plan
context.setFillColor(UIColor.systemBlue.cgColor)
context.fill(rect)
// Dessiner un cercle
context.setStrokeColor(UIColor.white.cgColor)
context.setLineWidth(4.0)
let circleRect = rect.insetBy(dx: 20, dy: 20)
context.strokeEllipse(in: circleRect)
}
Dans cet exemple, draw(_:) remplit le fond en bleu et dessine un cercle blanc avec une marge de 20 pixels par rapport aux bords. Chaque appel à draw(_:) doit être idempotent — des appels multiples avec les mêmes paramètres doivent produire le même résultat.
Apple recommande de minimiser le travail à l'intérieur de draw(_:) — créez UIBezierPath à l'avance, mettez en cache les images et n'effectuez pas de calculs lourds. Si la vue est statique, envisagez d'utiliser UIImageView avec une image rendue au lieu de redessiner constamment.
CALayer est la couche sous-jacente qui gère le contenu visuel d'UIView. De nombreuses tâches de dessin personnalisé peuvent être résolues en configurant les propriétés de CALayer sans redéfinir draw(_:), ce qui est nettement plus efficace.
Selon Apple Engineering (2024), les opérations au niveau de CALayer s'exécutent sur le GPU, tandis que draw(_:) fonctionne via le rendu Core Graphics basé sur le CPU. Pour les animations et les transitions fluides, il est préférable d'utiliser CALayer et CABasicAnimation.
| Scénario | Approche recommandée | Performances |
|---|---|---|
| Coins arrondis | layer.cornerRadius | GPU, élevées |
| Ombres et dégradés | CAGradientLayer, shadowPath | GPU, élevées |
| Formes arbitraires | CAShapeLayer avec UIBezierPath | GPU, élevées |
| Graphiques complexes | draw(_:) avec Core Graphics | CPU, moyennes |
| Texte avec formatage personnalisé | CATextLayer ou draw(_:) | Dépend du volume |
Utilisez CAShapeLayer pour dessiner des formes vectorielles avec animation — il est accéléré par le matériel et prend en charge l'animation de path, strokeStart et strokeEnd sans appeler draw(_:).
Les performances de Custom UIView affectent directement la fluidité des animations et l'expérience utilisateur globale. Les principaux problèmes proviennent d'appels excessifs à draw(_:), d'une disposition sous-optimale des sous-vues et d'un manque de mise en cache.
Chaque appel à setNeedsDisplay() déclenche un redessin complet de la vue. Utilisez setNeedsDisplay(_:) avec un rectangle spécifique si les modifications n'ont affecté qu'une partie de la vue. Pour les propriétés de CALayer (backgroundColor, cornerRadius, shadow), le redessin n'est pas nécessaire — elles sont mises à jour au niveau du GPU.
Si le contenu de Custom UIView change rarement, rendez-le une fois dans UIGraphicsImageRenderer et sauvegardez-le en tant qu'UIImage. Lors du prochain redessin, utilisez draw(at:) pour afficher l'image mise en cache — c'est des dizaines de fois plus rapide qu'un nouveau rendu via Core Graphics.
func renderToImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(size: bounds.size)
return renderer.image { ctx in
drawHierarchy(in: bounds, afterScreenUpdates: true)
}
}
La propriété shouldRasterize de CALayer active la mise en cache de la représentation matricielle de la couche. Activez-la pour les vues statiques avec transparence et ombres — cela réduit la charge de composition. Désactivez-la pour les vues animées : le cache se réinitialise à chaque modification et la rastérisation ne fait que dégrader les performances.
Foire aux questions
Non, draw(_:) n'est nécessaire que pour le dessin personnalisé via Core Graphics. Si la vue est composée de sous-vues standard (UILabel, UIImageView) et utilise CALayer, il n'est pas nécessaire de redéfinir draw(_:) — cela améliorera même les performances.
Placez une UIView ordinaire sur le canevas, dans l'Identity Inspector spécifiez votre classe dans le champ Class. Si la classe est marquée @IBDesignable, les modifications s'afficheront en temps réel directement dans le Storyboard.
init(frame:) est appelé lors de la création programmatique de la vue — vous passez un CGRect avec la position et la taille. init(coder:) est appelé lors de la désérialisation depuis le Storyboard ou XIB. Pour un fonctionnement correct, les deux doivent être implémentés, sinon votre vue plantera lors du chargement depuis Interface Builder.
La raison la plus courante est que la vue a un cadre nul (largeur ou hauteur égale à zéro). Le système n'appelle pas draw(_:) pour les vues avec des dimensions nulles. Vérifiez le cadre dans layoutSubviews() et assurez-vous que la vue a été ajoutée à la hiérarchie avec des contraintes correctes.
Utilisez CALayer pour les propriétés qui prennent en charge l'animation sur GPU (position, opacity, transform). Pour les mises à jour partielles de draw(_:), utilisez setNeedsDisplay(_:) avec un CGRect de la zone modifiée — le système ne redessinera que la région spécifiée, pas la vue entière.
Résumé
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.
Lisez aussi