Swift HStack View not conforming to protocol 'View'
I have built this code
struct StarDifficultyView: View {
var numberOfStarsToShow: Int
var numberOfTotalStarsToShow: Int = 5
var body: some View {
HStack{
var numberLeftToShow = numberOfStarsToShow
ForEach(1..<numberOfTotalStarsToShow+1){_ in
if(numberLeftToShow > 0){
Image(systemName: "star.fill")
.foregroundColor(Color.yellow)
numberLeftToShow -= 1
}else{
Image(systemName: "star.fille")
.foregroundColor(Color.yellow)
}
}
}
}
}
It gives me an error on the line if(numberLeftToShow > 0){
saying "Type '()' cannot conform to 'View'"
Can anyone tell me what I'm doing wrong
Solution 1:
Explaining the issue:
You should not add expressions inside the view builder. So numberLeftToShow -= 1
will throw and error because it returns a void
('aka' type()) and this does not conform to View
! that is the exact reason for the compiler!
Note 1
Don't use SwiftUI like the UIKit! SwiftUI views may execute over time on any state change and should not be used for calculating anything in this way
Note 2
You can convert 1..<numberOfTotalStarsToShow+1
to a closed range like 1...numberOfTotalStarsToShow
(Although you don't need it at all for this question)
Note 3
Try not to use branch and convert your if/else code to something like:
Image(systemName: numberLeftToShow > 0 ? "star.fill" : "star.fille")
.foregroundColor(Color.yellow)
Note 4:
The lower bound of a range can not be less than the upper range, but you can iterate over a reversed range like:
(1...numberOfTotalStarsToShow).reversed()
Note 5:
try using a single source of truth like the forEach parameter itself!
Note 6:
Swift can infer the type and you don't need to pass it again:
so change Color.yellow
to .yellow
Final Result:
Here is the code reviewed answer (based on the answer you have provided yourself):
var body: some View {
HStack {
ForEach(1...numberOfTotalStarsToShow, id:\.self) { i in
Image(systemName: "star.fill")
.foregroundColor(i > numberOfStarsToShow ? .gray : .yellow)
}
}
}
Solution 2:
Don't throw away the closure parameter for the ForEach
!
var body: some View {
HStack{
ForEach(0..<numberOfTotalStarsToShow){ i in // don't ignore the "i" here by writing "_"
// "i" will be different in each "iteration"
// use that to figure out which image to show
if(i < numberOfStarsToShow){
Image(systemName: "star.fill")
.foregroundColor(Color.yellow)
} else {
Image(systemName: "star")
.foregroundColor(Color.yellow)
}
}
}
}