Un indicateur circulaire de progression bien conçu améliore significativement la clarté et l’engagement utilisateur dans les applications iOS. Ce guide explore une bibliothèque moderne, écrite entièrement en Swift, conçue pour offrir un contrôle précis sur l’apparence, le comportement et les animations de ce type d’élément d’interface.
Présentation de la bibliothèque
La bibliothèque fournit une implémentation native de ProgressRing, une vue personnalisable qui s’intègre naturellement dans les projets SwiftUI ou UIKit. Elle ne dépend pas de couches graphiques externes ni de rendu basé sur Core Graphics manuel, ce qui garantit une performance fluide même lors de mises à jour fréquentes du pourcentage.
Intégration dans votre projet
Pour intégrer la bibliothèque via Swift Package Manager, ajoutez l’URL du dépôt dans Xcode (File > Add Packages…) :
https://github.com/gh-mirrors/ui/UICircularProgressRing.git
Vous pouvez également utiliser SwiftPM depuis un fichier Package.swift :
dependencies: [
.package(url: "https://github.com/gh-mirrors/ui/UICircularProgressRing.git", from: "8.0.0")
]
Création d’un indicateur de base
L’initialisation se fait avec une valeur normalisée entre 0 et 1, accompagnée de deux styles distincts pour les anneaux intérieur et extérieur :
let ring = ProgressRing(
progress: 0.62,
outerStyle: RingAppearance(
tint: .systemGray,
thickness: 28
),
innerStyle: RingAppearance(
tint: .systemIndigo,
thickness: 14,
spacing: 6
)
)
Personnalisation visuelle approfondie
Chaque anneau est configuré via une structure RingAppearance, qui encapsule :
- tint : couleur appliquée (supporte les systèmes de couleurs dynamiques)
- thickness : épaisseur du trait, en points logiques
- spacing : espace entre les deux anneaux
- cap : forme des extrémités du trait (
.round,.square) - dashed : tableau de segments pour un tracé en pointillés
Exemple de style ponctué :
let dashedRing = RingAppearance(
tint: .systemTeal,
thickness: 18,
cap: .round,
dashed: [4, 6]
)
Mode indéterminé et animation continue
Pour les états de chargement sans progressino mesurable, utilisez IndeterminateRing. Ce composant anime automatiquement une rotation continue avec une trajectoire elliptique subtile :
IndeterminateRing(
speed: 0.8,
lineWidth: 22
)
Le paramètre speed ajuste la vitesse relative de l’animation (valeur par défaut : 1.0).
Intégration avec les animations SwiftUI
Les transitions de progression sont gérées nativement via les modificateurs animation(_:value:) ou withAnimation. Pour une interpolation fluide :
@State private var value: Double = 0.0
var body: some View {
ProgressRing(progress: value, ...)
.animation(.easeOut(duration: 0.7), value: value)
Button("Avancer") {
value = min(1.0, value + 0.25)
}
}
Adaptation au contexte d’utilisation
Le composant s’adapte à divers scénarios grâce à des extensions spécialisées :
- Téléchargement : affichage combiné avec un texte dynamique (ex.
"37 Mo / 92 Mo") - Objectif quotidien : combinaison avec un badge de statut (ex. « ✅ Atteint »)
- Minuteur : liaison à un
Timerou à unePublisherCombine pour mise à jour en temps réel
Contrôle des dimensions et du positionnement
La taille du cercle est contrôlée via le modificateur .frame(). Contrairement aux vues basées sur des contraintes fixes, cette approche permet un redimensionnement réactif selon les traits d’appareil ou les orientations :
ProgressRing(progress: 0.45)
.frame(width: 180, height: 180)
.padding(.horizontal, 16)
Personnalisation du texte central
Le texte affiché au centre peut être entièrement remplacé. L’API accepte une fermeture retournant un some View, ce qui autorise des compositions complexes :
ProgressRing(
progress: 0.77,
centerContent: {
VStack(spacing: 4) {
Text("\(Int(0.77 * 100))%")
.font(.headline)
.fontWeight(.semibold)
Text("Terminé")
.font(.caption)
.foregroundColor(.secondary)
}
}
)