Origine
Récemment, j'ai voulu porter mon mini-programme WeChat "花瓣单词挑战" sur iOS. Ce jeu consiste à former des mots en tapant sur des lettres disposées sur des pétales. Si dessiner des pétales en CSS était simple, passer à SwiftUI m'a donné des migraines.
En tant que développeur SwiftUI intermédiaire - n'ayant créé que quelques applications basiques - je ne savais même pas par où commencer pour dessiner un pétale. Après avoir cherché "SwiftUI pétale" sur Google, j'ai trouvé cet article. Bien que différent de ce que je voulais, il m'a donné une piste.
Qu'est-ce que le protocole Shape ?
En bref, le protocole Shape de SwiftUI permet de créer des formes personnalisées. Il suffit d'implémenter la méthode path(in rect: CGRect) -> Path
pour définir le tracé.
Première tentative : Dessiner des arcs avec addArc
L'article utilisait la méthode addArc
:
struct DaisyPental: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: rect.minX, y: rect.midY))
path.addArc(
center: CGPoint(x: rect.maxX, y: rect.midY),
radius: rect.maxX*(1/11),
startAngle: .degrees(90),
endAngle: .degrees(270),
clockwise: true
)
return path
}
}
Pour comprendre ce code, je l'ai testé dans Xcode avec un fond rouge :
struct ShapTest: View {
var body: some View {
DaisyPental()
.fill(.yellow.gradient)
.frame(width: 110, height: 20)
.background(.red) // Fond rouge pour visualisation
}
}
Le système de coordonnées de SwiftUI est contre-intuitif
Attention à ce piège : le système de coordonnées fonctionne différemment :
- Origine en haut à gauche : Pas en bas à gauche
- Axe X : Positif vers la droite (normal)
- Axe Y : Positif vers le bas (contre-intuitif !)
Ainsi :
rect.minX
,rect.minY
→ Coin supérieur gaucherect.maxX
,rect.maxY
→ Coin inférieur droitrect.midX
,rect.midY
→ Centre
Vous pouvez expérimenter en modifiant les valeurs dans path.move
avec l'aperçu Xcode.
Les angles d'addArc sont encore plus contre-intuitifs
La définition des angles pour addArc
est particulière :
- 0° → Droite
- 90° → Bas (Pas le haut !)
- 180° → Gauche
- 270° → Haut
Totalement différent du système mathématique standard.
addQuadCurve : L'outil ultime pour les courbes
J'ai réalisé que addArc
ne pouvait pas créer mon pétale. En voyant addQuadCurve
sur YouTube, je l'ai testé avec succès :
path.addQuadCurve(
to: CGPoint, // Point final
control: CGPoint // Point de contrôle
)
- Point de départ : Position actuelle du crayon
- Point final : Destination de la courbe
- Point de contrôle : Détermine la courbure
Ajustez le point de contrôle pour modifier la courbe visuellement.
Mon implémentation finale du pétale
Après expérimentation, j'ai obtenu cette forme :
import SwiftUI
struct PetalShape: Shape {
func path(in rect: CGRect) -> Path {
Path { path in
// Point de départ
path.move(to: CGPoint(x: rect.minX + 30, y: rect.minY + 30))
// Courbe gauche du pétale
path.addQuadCurve(
to: CGPoint(x: rect.minX + 30, y: rect.minY - 30),
control: CGPoint(x: rect.minX - 10, y: rect.minY)
)
// Pointe du pétale
path.addQuadCurve(
to: CGPoint(x: rect.maxX * 1.8, y: rect.minY),
control: CGPoint(x: rect.midX + 40, y: -rect.maxY + 30)
)
// Côté droit (retour au départ)
path.addQuadCurve(
to: CGPoint(x: rect.minX + 30, y: rect.minY + 30),
control: CGPoint(x: rect.midX + 40, y: rect.maxY - 30)
)
}
}
}
Exemple d'utilisation :
struct ShapeTest: View {
var body: some View {
PetalShape()
.fill(.yellow.gradient)
.frame(width: 110, height: 110)
}
}
Prochaine étape : Composer la fleur complète
Avec un pétale prêt, composer une fleur est simple :
- Dupliquer plusieurs pétales
- Les faire pivoter avec
rotationEffect
- Ajuster la position avec
offset
- Les assembler en une fleur
Leçons apprises
Conclusions clés :
- Système de coordonnées : Particulièrement contre-intuitif
- addQuadCurve > addArc : Bien supérieur pour les courbes naturelles
- Point de contrôle crucial : L'expérimentation est essentielle
- Aperçu en direct indispensable : Utilisez constamment le Canvas
En conclusion
J'ai finalement créé la forme de pétale et continue le développement de "花瓣单词挑战" pour iOS, visant une sortie prochaine.
J'ai écrit cet article pour documenter le processus. Si vous travaillez avec des formes SwiftUI personnalisées, j'espère que cela vous aidera !