简体   繁体   中英

How to animate particular button from ForEach in SwiftUI?

I have a problem with animating buttons. I have them created using ForEach method. The layout of my app consists of 3 flags. We have text that is saying that we have to choose a flag of particular country and if we choose the correct one we gain points.

I want to animate particular button when it is pressed. Doesn't matter if the answer is correct or not.

My code for creating these buttons looks like this:

ForEach(0 ..< 3) { number in
    Button(action: {
        withAnimation {
            if number == self.correctAnswer {
                self.animationAmount += 360
            }
        }
        
        self.flagTapped(number)
    }) {
        ImageView(myImage: self.countries[number])
    }
    .rotation3DEffect(.degrees(number == self.correctAnswer ? self.animationAmount : 0), axis: (x: 0, y: 1, z: 0))
    .opacity(self.showAnimation && number != self.correctAnswer ? 0.25 : 1)
    .background(self.showAnimation && number != self.correctAnswer ? Color.red: nil)
}

self.flagTapped(number) toggles showAnimation to be true .

Here is possible alternate approach - more appropriate looks to move button into separated view and let it animate itself when needed.

Demo prepared on some replicated simplified code (due to absent parts in provided snapshot). Tested with Xcode 12 / iOS 14.

演示

struct DemoView: View {
    let countries = ["flag-1", "flag-2", "flag-3", "flag-4"]

    @State private var number: Int = -1
    let correctAnswer = 1
    var body: some View {
        VStack {
            ForEach(0 ..< 3) { number in
                FlagButton(number: number, image: self.countries[number], answer: correctAnswer){
                    self.flagTapped(number)
                }
            }
        }
    }

    private func flagTapped(_ number: Int) {
        self.number = number
    }
}


struct FlagButton: View {
    let number: Int
    let image: String
    let answer: Int
    var showAnimation = false
    let action: () -> ()

    @State private var animationAmount = Double.zero
    var body: some View {
        Button(action: {
            if self.number == self.answer {
                self.animationAmount += 360
            }
            action()
        }) {
            Image(image)
        }
        .rotation3DEffect(.degrees(number == answer ? self.animationAmount : 0), axis: (x: 0, y: 1, z: 0))
        .opacity(self.showAnimation && number != answer ? 0.25 : 1)
        .background(self.showAnimation && number != answer ? Color.red: nil)
        .animation(.default)
    }
}

backup

@State private var selectedFlag = -1 //Add this in your ContentView struct
ForEach(0..<3) { number in
                    Button {
                        flagTapped(number)
                        noOfQuestions += 1
                        if noOfQuestions == 8 {
                            showingEnd = true
                        }
                        if scoreTitle == "Correct Answer" {
                            score += 1
                        }
                    } label: {
                        Image(countries[number])
                            .renderingMode(.original)
                            .clipShape(Capsule())
                            .shadow(radius: 5)
                            .rotation3DEffect(.degrees(selectedFlag == number ? 360 : 0),
                                              axis: (x: 0, y:1, z:0))
                            .opacity((selectedFlag == number || selectedFlag == -1) ? 1 : 0.25)
                            .animation(.default, value: selectedFlag )
                            .scaleEffect((selectedFlag == number || selectedFlag == -1) ? 1 : 0.75)
                    }
                }

The selectedFlag var will help determine which of the flags is in currently chosen and applying animations to the specific images rather than the buttons works best.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM