I have a custom bounce animation applied to a view with multiple inner views which can change depending on conditions. My issue is that when the inner view changes, the animation applied to a parent no longer applies to it.
Example:
Sample Code:
struct ContentView: View {
@State var number = 1
var body: some View {
VStack {
ZStack {
Circle()
.foregroundColor(.gray)
.frame(width: 100, height: 100, alignment: .center)
if number == 1 {
Image(systemName: "person")
}
else if number == 2 {
ProgressView()
}
else {
EmptyView()
}
}
.bounceEffect()
Button {
if number != 3 {
number += 1
}
else {
number = 1
}
} label: {
Text("CHANGE")
}
.padding()
}
.padding()
}
}
struct BounceEffect: ViewModifier {
@State var bounce = false
var allow: Bool
func body(content: Content) -> some View {
content
.offset(y: (bounce && allow) ? -5 : 0)
.animation(.interpolatingSpring(mass: 1, stiffness: 350, damping: 5, initialVelocity: 10).repeatForever(autoreverses: false).delay(1), value: UUID())
.onAppear {
if allow {
bounce.toggle()
}
}
}
}
extension View {
func bounceEffect(allow: Bool = true) -> some View {
modifier(BounceEffect(allow: allow))
}
}
Thank you.
2
Answers
The reason of the bounceEffect don’t get the button after you change because you are creating the new image when ever you tap the button
change
.The action you need here: just only change the system image of the image not creating new one every time the button
change
is tappedThe code will be like this
The result
When the new images appear, they aren’t the ones involved in the animation. One way to fix this is to include all 3 images from the start, and just cycle their visibility by changing
opacity
:@bewithyou’s answer is more scalable and should be the accepted answer. Here is a better way to structure the selection of your images: