Chained animations messing up on orientation change

Viewed 81

When I change the orientation the sparkle SF symbol starts moving up and down. The up and down animation is only supposed to be implemented once (on appearance). I have tried using verticalSizeClass however, that does not help.

Way it works: on appearance, the text and the SF symbol moves up and then the Sparkle SF symbol scales up and down.

This is how it looks and behaves on orientation change:

enter image description here

struct ContentView: View {
    @State private var offsetY: CGFloat = 150
    @State private var opacityAmount: Double = 0
    @State private var animationAmount: CGFloat = 1
    
    var body: some View {
        VStack {
            HStack {
                Image(systemName: "sparkle").foregroundColor(.yellow)
                    .offset(y: offsetY)
                    .opacity(opacityAmount)
                    .animation(
                        Animation.easeOut(duration: 0.5).delay(0.1)
                    )
                    .scaleEffect(animationAmount)
                    .animation(Animation.easeInOut(duration: 1).repeatForever(autoreverses: true))
                Text("All new design").font(.largeTitle)
                    .offset(y: offsetY)
                    .opacity(opacityAmount)
                    .animation(
                        Animation.easeOut(duration: 0.5).delay(0.1)
                    )
            }
            .onAppear {
                offsetY = 0
                opacityAmount = 0.8
                animationAmount = 2
            }
        }
    }
}
1 Answers

You did not adapt animation-value join from my previous answer, and observe result of that.

It is because .animation modifier introduces implicit animation, which is applied to all animatable view modifiers above it, that might ended up with undesired accumulated multiple animations (however sometimes it is what's needed, of course).

Here is fixed part. Tested with Xcode 12 / iOS 14

HStack {
    Image(systemName: "sparkle").foregroundColor(.yellow)
        .offset(y: offsetY)
        .opacity(opacityAmount)
        .animation(
            Animation.easeOut(duration: 0.5).delay(0.1)
        , value: opacityAmount)                     // << here !!
        .scaleEffect(animationAmount)
        .animation(Animation.easeInOut(duration: 1).repeatForever(autoreverses: true),
            value: animationAmount)                // << here !!
    Text("All new design").font(.largeTitle)
        .offset(y: offsetY)
        .opacity(opacityAmount)
        .animation(
            Animation.easeOut(duration: 0.5).delay(0.1)
        , value: opacityAmount)                           // << here !!
}

Note: you can play with which animation to give explicit value or not.

Related