Reputation: 159
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
.
Upvotes: 3
Views: 1220
Reputation: 257493
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)
}
}
Upvotes: 3
Reputation: 11
@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.
Upvotes: 1