我正在尝试向我正在编写的应用程序添加评级系统。我的方法不太优雅,使用Stepper
。如果可能的话,我想要一种交互式拖动方式来填充星级。
我不确定是否DragGesture
是我正在寻找的,这足够吗?另外,我不确定如何将坐标转换为正确的宽度以填充星星。任何帮助,将不胜感激。
struct ContentView: View {
@State var rating: Double = 0.0
var body: some View {
VStack {
HStack(spacing: 3) {
let stars = HStack(spacing: 0) {
ForEach(0..<5) { _ in
Image(systemName: "star.fill")
.font(.title3)
}
}
stars.overlay(
GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle()
.frame(width: CGFloat(rating / 2) / 5 * geometry.size.width)
.foregroundColor(Color.yellow)
}
}.mask(stars)
).foregroundColor(Color.secondary)
}
Stepper("Rating \(String(format: "(%.0f%%)", rating * 10))", value: $rating, in: 0...10, step: 0.5)
}
.padding()
Spacer()
.frame(height: 100)
HStack(spacing: 3) {
let stars = HStack(spacing: 0) {
ForEach(0..<5) { _ in
Image(systemName: "star.fill")
.font(.title3)
}
}
stars.overlay(
GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle()
.frame(width: CGFloat(rating / 2) / 5 * geometry.size.width)
.foregroundColor(Color.yellow)
}
}.mask(stars)
).foregroundColor(Color.secondary)
.gesture(
DragGesture(minimumDistance: 0)
.onEnded { end in
if (end.location.x - end.startLocation.x) > 0 {
print("Right")
} else {
print("Left")
}
})
}
}
}
我使用圆形作为剪辑形状,但其余的应该做你想要的。
如果将 @State 评级更改为 @Binding,则可以将其称为子视图。
struct ContentView: View {
@State var rating = 50.0
var body: some View {
VStack {
Text("Your Rating \(rating, specifier: "%.0f")")
GeometryReader { geo in
HStack(spacing: 0) {
Color.yellow
.frame(width: geo.size.width * rating / 100)
Color.gray
.frame(width: geo.size.width * (100 - rating) / 100)
}
.gesture(
DragGesture()
.onChanged({ value in
rating = ((value.translation.width + value.startLocation.x)
/ geo.size.width * 100.0)
rating = min(100, max(rating, 0))
})
)
.clipShape(RatingClipShape())
}
.frame(height: 80)
}
.padding(30)
}
}
struct RatingClipShape: Shape {
let paddingAmount = 5.0 // %
func path(in rect: CGRect) -> Path {
let padding = rect.width * paddingAmount / 100
let diameter = (rect.width - (4 * padding)) / 5
let step = diameter + padding
var path = Path()
for i in 0..<5 {
path.addEllipse(in: CGRect(x: Double(i)*step, y: 0, width: diameter, height: diameter))
}
return path
}
}
Result:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)