import SwiftUI
struct RatingStars: View {
@State var starState : Int
var body: some View {
HStack{
ForEach(0..<starState){ index in
Button{
self.starState = index
} label :{
Text("★")
.font(.system(size: 30))
}
}
ForEach(0..<5-starState){ index in
Button{
self.starState = index
} label :{
Text("☆")
.font(.system(size: 30))
}
}
}.padding()
}
}
I am implementing a ui where two stars are filled when the second star is pressed.
I am expecting the view to be redrawn when the starState variable changes.
Now my code doesn't change much when I press the star. What's the problem?
CodePudding user response:
When using ForEach
you need to provide objects that are identifiable. In your case you can use the integer itself so ForEach(0..<starState)
becomes ForEach(0..<starState, id: \.self)
.
PS: You have another problem: you use separate ForEach
s which will provide you with different indexes. You can resolve this by merging them into one like this:
ForEach(0..<5, id: \.self){ index in
Button{
self.starState = index
} label :{
let star = index <= starState ? "★" : "☆"
Text(star)
.font(.system(size: 30))
}
}
CodePudding user response:
A slightly different answer than @LeoDabus, but the same idea:
struct RatingStars: View {
@State var starState = 2
var body: some View {
HStack{
ForEach(0..<5, id: \.self) { index in
Button{
starState = starState == index ? starState - 1 : index
} label :{
index <= starState ? Text("★").font(.system(size: 30)) : Text("☆").font(.system(size: 30))
}
}
}
.padding()
}
}
CodePudding user response:
Besides the lack of an identifier in your ForEach as already mentioned here you can simply add a long press gesture to your text view and onChange set your starState to index 1
. When setting your text string you can use a ternary operator as suggested by @spasbil but use less then to fix the initial state issue of his post:
ForEach(0..<5, id: \.self) { index in
Text(index < starState ? "★" : "☆")
.font(.system(size: 30))
.gesture(LongPressGesture().onChanged { _ in
starState = index 1
})
}
edit/update:
If you would like to be able to toggle the current star as well:
struct ContentView: View {
@State var starState : Int
var body: some View {
HStack {
ForEach(0..<5, id: \.self) { index in
Text(index < starState ? "★" : "☆")
.font(.system(size: 30))
.gesture(LongPressGesture().onChanged { _ in
starState = index 1 == starState ? starState - 1 : index 1
})
}
}.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(starState: 1)
}
}