Home > Blockchain >  Swift HStack View not conforming to protocol 'View'
Swift HStack View not conforming to protocol 'View'

Time:01-23

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

CodePudding user response:

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

CodePudding user response:

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

CodePudding user response:

Never mind, I just did this

struct StarDifficultyView: View {

    var numberOfStarsToShow: Int
    var numberOfTotalStarsToShow: Int = 5

    var body: some View {
        HStack{
            ForEach(1..<numberOfStarsToShow 1){_ in
                Image(systemName: "star.fill")
                    .foregroundColor(Color.yellow)
            }
            ForEach(1..<numberOfTotalStarsToShow-numberOfStarsToShow 1){_ in
                Image(systemName: "star.fill")
                    .foregroundColor(Color.gray)
                    .opacity(0.7)
            }
        }
    }
}

Basically, it just loops through the number of yellow stars to show and then works out how many grey ones to show and does another ForEach to display the leftover ones needed

  •  Tags:  
  • Related