Comment créer une forme SwiftUI RoundedStar?
C'est une question auto-répondue qui est parfaitement acceptable (et même encouragée) sur Stack Overflow. Le but est de partager quelque chose d'utile avec les autres.
SwiftUI a un RoundedRectangle Shape. Ce serait bien d'avoir une étoile à cinq branches avec des pointes arrondies qui pourraient être utilisées pour le remplissage, le découpage et l'animation.
Cette réponse Stack Overflow montre comment créer une utilisation RoundedStarpersonnalisée .UIViewUIBezierPath
Comment ce code peut-il être adapté en SwiftUItant que Shapequi peut être animé?
Réponses
Voici le RoundedStarcode adapté en SwiftUI animable Shape:
// Five-point star with rounded tips
struct RoundedStar: Shape {
var cornerRadius: CGFloat
var animatableData: CGFloat {
get { return cornerRadius }
set { cornerRadius = newValue }
}
func path(in rect: CGRect) -> Path {
var path = Path()
let center = CGPoint(x: rect.width / 2, y: rect.height / 2)
let r = rect.width / 2
let rc = cornerRadius
let rn = r * 0.95 - rc
// start angle at -18 degrees so that it points up
var cangle = -18.0
for i in 1 ... 5 {
// compute center point of tip arc
let cc = CGPoint(x: center.x + rn * CGFloat(cos(Angle(degrees: cangle).radians)), y: center.y + rn * CGFloat(sin(Angle(degrees: cangle).radians)))
// compute tangent point along tip arc
let p = CGPoint(x: cc.x + rc * CGFloat(cos(Angle(degrees: cangle - 72).radians)), y: cc.y + rc * CGFloat(sin(Angle(degrees: (cangle - 72)).radians)))
if i == 1 {
path.move(to: p)
} else {
path.addLine(to: p)
}
// add 144 degree arc to draw the corner
path.addArc(center: cc, radius: rc, startAngle: Angle(degrees: cangle - 72), endAngle: Angle(degrees: cangle + 72), clockwise: false)
// Move 144 degrees to the next point in the star
cangle += 144
}
return path
}
}
Le code est très similaire à la UIBezierPathversion sauf qu'il utilise le nouveau Angletype qui fournit un accès facile à la fois degreeset radians. Le code pour dessiner l'étoile pivotée a été supprimé car il est facile d'ajouter une rotation à une forme SwiftUI avec le .rotationEffect(angle:)modificateur de vue.
Manifestation:
Voici une démonstration qui montre les qualités animables du cornerRadiusdécor et montre à quoi ressemblent les différents cornerRadiusréglages sur une étoile en plein écran.
struct ContentView: View {
@State private var radius: CGFloat = 0.0
var body: some View {
ZStack {
Color.blue.edgesIgnoringSafeArea(.all)
VStack(spacing: 40) {
Spacer()
RoundedStar(cornerRadius: radius)
.aspectRatio(1, contentMode: .fit)
.foregroundColor(.yellow)
.overlay(Text(" cornerRadius: \(Int(self.radius)) ").font(.body))
HStack {
ForEach([0, 10, 20, 40, 80, 200], id: \.self) { value in
Button(String(value)) {
withAnimation(.easeInOut(duration: 0.3)) {
self.radius = CGFloat(value)
}
}
.frame(width: 50, height: 50)
.foregroundColor(.black)
.background(Color.yellow.cornerRadius(8))
}
}
Spacer()
}
}
}
}
Exécution dans Swift Playgrounds sur iPad
Cela fonctionne à merveille sur un iPad dans l'application Swift Playgrounds. Il suffit d'ajouter:
import PlaygroundSupport
en haut et
PlaygroundPage.current.setLiveView(ContentView())
à la fin.
Utilisation de la forme RoundedStar pour créer un drapeau européen
struct ContentView: View {
let radius: CGFloat = 100
let starWidth: CGFloat = 36
let numStars = 12
var body: some View {
ZStack {
Color.blue
ForEach(0..<numStars) { n in
RoundedStar(cornerRadius: 0)
.frame(width: starWidth, height: starWidth)
.offset(x: radius * cos(CGFloat(n) / CGFloat(numStars) * 2 * .pi), y: radius * sin(CGFloat(n) / CGFloat(numStars) * 2 * .pi))
.foregroundColor(.yellow)
}
}
}
}