UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Animation Challenge #1

Forums > 100 Days of SwiftUI

I'm working on Animation Challenge #1. The ask is to modify the Guess the Flag project so that when you tap a flag it spins around 360 degrees on the Y axis.

Seems easy enough but when I try to add an animation modifier to button the in Guess the Flag (which I put before the label code), I get the following error: Trailing closure passed to parameter of type 'PrimitiveButtonStyleConfiguration' that does not accept a closure.

To try an figure out why I was getting the error I removed the animation modifier and commented out the label code and get that error as well.

Can someone explain why the error and why I can't add an animation modifier to the button?

struct ContentView: View {
    @State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"].shuffled()
    @State private var correctAnswer = Int.random(in: 0...2)
    @State private var showingScore = false
    @State private var scoreTitle = ""
    @State private var userScore = 0
    @State private var numberOfTaps = 1
    @State private var lastQuestion = false
    @State private var animationAmount = 2.0

    var body: some View {
        ZStack {
            /*LinearGradient(gradient: Gradient(colors: [.green, .gray, .blue]), startPoint: .top, endPoint: .bottom)
                    .ignoresSafeArea()*/

            RadialGradient(stops: [
                .init(color: Color(red: 0.1, green: 0.2, blue: 0.45), location: 0.3),
                .init(color: Color(red: 0.76, green: 0.15, blue: 0.26), location: 0.3),
            ], center: .top, startRadius: 200, endRadius: 400)
                .ignoresSafeArea()
            VStack  {
                Spacer()
                Text("Guess the Flag")
                    .viewTitleStyle()
                //.font(.largeTitle.bold())
                    //.foregroundColor(.white)

                VStack(spacing: 15) {
                    VStack {
                        Text("Tap the flag of ")
                            .font(.subheadline.weight(.medium))
                            .foregroundStyle(.secondary)
                        Text(countries[correctAnswer])
                            .font(.largeTitle.weight(.semibold))
                            //.foregroundColor(.white)
                    }
                    ForEach(0..<3) {number in
                        Button {
                            flagTapped(number)
                        } .animation(.easeIn, value: animationAmount)
                        /*label: {
                            FlagImage(image: countries[number])
                                //.renderingMode(.original)
                                //.clipShape(Capsule())
                                //.shadow(radius: 5)
                            }*/
                    }
                }
                .frame(maxWidth: .infinity)
                    .padding(.vertical, 20)
                    .background(.regularMaterial)
                    .clipShape(RoundedRectangle(cornerRadius: 20))
                Spacer()
                Spacer()
                Text("Score: \(userScore)")
                    .foregroundColor(.white)
                    .font(.title.bold())
                Spacer()
            }
            .padding()
        }
        .alert(scoreTitle, isPresented: $showingScore) {
            Button("Continue", action: askQuestion)
        } message: {
            Text("Your score is now \(userScore)")
        }
        .alert("Game Over", isPresented: $lastQuestion) {
                    Button("Restart Game", action: resetScore)
                } message: {
                    if userScore > 6 {
                        Text("Your final score is \(userScore). Great job!")
                    } else if userScore > 4 {
                        Text("Your final score is \(userScore). Not bad")
                    } else {
                        Text("Your final score is \(userScore). You need to study a bit")
                    }
                }
    }

    func flagTapped(_ number: Int) {
        if number == correctAnswer && numberOfTaps < 8 {
            scoreTitle = "Correct"
            userScore += 1
            numberOfTaps += 1
            showingScore = true
        } else if number != correctAnswer && numberOfTaps < 8 {
            scoreTitle = "Wrong. That's the flag of  \(countries[number]). You lose a point."
            userScore -= 1
            numberOfTaps += 1
            showingScore = true
        } else if number == correctAnswer {
            scoreTitle = "Correct"
            userScore += 1
            lastQuestion =  true
        } else {
            scoreTitle = "Wrong. That's the flag of  \(countries[number]). You lose a point."
            userScore -= 1
            lastQuestion = true
        }
    }
    func askQuestion() {
        countries.shuffle()
        correctAnswer = Int.random(in: 0...2)
    }
    func resetScore() {
        countries.shuffle()
        correctAnswer = Int.random(in: 0...2)
        userScore = 0
        numberOfTaps = 0
    }
}

struct FlagImage: View {
    var image: String

    var body: some View {
        Image(image)
            .renderingMode(.original)
            .clipShape(Rectangle())
            .shadow(radius: 5)
    }
}

struct ViewTitle: ViewModifier {
    func body(content: Content) -> some View {
        content
            .font(.largeTitle)
            .foregroundColor(.white)
    }
}

extension View {
    func viewTitleStyle() -> some View {
        modifier(ViewTitle())
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

1      

You have placed the animation modifier in the wrong place; it is between two parameters of your Button.

You are using this initializer on Button:

init(action: @escaping () -> Void, label: () -> Label)

which looks like this in use:

Button(action: {
    //this is the action closure
}, label: {
    //this is the label closure
})

or, with multiple trailing closures:

Button {
    //this is the action closure
} label: {
    //this is the label closure
}

You can't put a modifer in between the two parameters action and label. You either need to put it, depending on what the modifier is doing, after both parameters:

Button {
    //this is the action closure
} label: {
    //this is the label closure
}
.modifier(...)

or on something inside the label parameter:

Button {
    //this is the action closure
} label: {
    //this is the label closure
    Text("or whatever")
        .modifier(...)
}

1      

Much appreciate @roosterboy.

1      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.