Home > front end >  count stars in swiftUI
count stars in swiftUI

Time:02-23

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()
        
    }
}

enter image description here

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 ForEachs 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)
    }
}
  • Related