Jak stworzyć SwiftUI RoundedStar Shape?
To pytanie, na które można odpowiedzieć samodzielnie, jest całkowicie akceptowalne (a nawet zalecane) w witrynie Stack Overflow. Chodzi o to, aby podzielić się czymś pożytecznym dla innych.
SwiftUI ma RoundedRectangle Shape. Byłoby miło mieć pięcioramienną gwiazdę z zaokrąglonymi końcówkami, których można by użyć do wypełniania, przycinania i animacji.
Ta odpowiedź na przepełnienie stosu pokazuje, jak utworzyć RoundedStarniestandardowy plik UIViewusing UIBezierPath.
Jak to może być dostosowany do kodu SwiftUIjako Shapeże może być animowany?
Odpowiedzi
Oto RoundedStarkod zaadaptowany jako animowany interfejs SwiftUI 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
}
}
Kod jest bardzo podobny do UIBezierPathwersji, z tym wyjątkiem, że używa nowego Angletypu, który zapewnia łatwy dostęp do obu degreesi radians. Kod do rysowania obróconej gwiazdy został usunięty, ponieważ łatwo jest dodać obrót do kształtu SwiftUI za pomocą .rotationEffect(angle:)modyfikatora widoku.
Demonstracja:
Oto demonstracja, która pokazuje animowane cechy cornerRadiusscenerii, a także pokazuje, jak różne cornerRadiusustawienia wyglądają na gwiazdę pełnoekranową.
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()
}
}
}
}
Bieganie w Swift Playgrounds na iPadzie
Działa to pięknie na iPadzie w aplikacji Swift Playgrounds. Poprostu dodaj:
import PlaygroundSupport
u góry i
PlaygroundPage.current.setLiveView(ContentView())
na końcu.
Używanie kształtu RoundedStar do tworzenia flagi UE
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)
}
}
}
}