2

I am new to SwiftUI (and the whole iOS Development in general). I learned that to animate a view in SwiftUI you can do:

MyView()
    .scaleEffect(scaleValue)
    .onAppear {
        scaleValue = anotherValue
    }
    .animation(.spring())

But I can't seem to figure out how I could listen to when this animation ends so I could trigger some other things such as run a different animation or do some netwrok request.

Can anyone guide me please? Is there a callback I could attach to this so I could be notified with the end of the animation?

Thanks in advance.

Archie G. Quiñones
  • 11,638
  • 18
  • 65
  • 107

1 Answers1

0

To my knowledge there is not-yet a direct way to do a sequence of animations. This is more of a workaround than an actual solution, But it works, and its not too complicated.

Assuming you have a variable @State var animatedVariable, when you want to apply animation to UI changing with the changes of your animatedVariable, you can say withAnimation { animatedVariable = someNewValue }. now if you want to do another animation after the first one completes, you should declare a new variable first: @State var delayedAnimatedVariable and you can use it anywhere you want that delayed animation to be applied. to make it work, you better not set the value of delayedAnimatedVariable directly. instead, you should listen to changes of animatedVariable and change the value of delayedAnimatedVariable with a delayed animation. for that, you should use .onChange(available Xcode 12+) modifier:

.onChange(of: animatedVariable) { newValueOfAnimatedVariable in
    withAnimation(Animation.default.delay(0.25)) {
        delayedAnimatedVariable = newValueOfAnimatedVariable
    }
}

EXAMPLE:

struct AnimatedView: View {
    
    @State var animatedVariable = ""
    @State var delayedAnimatedVariable = ""
    
    var body: View {
        VStack {
            Button("Animated with delay!") {
                withAnimation {
                    animatedVariable = "someNewValue"
                }
            }
            
            // everything that uses `delayedAnimatedVariable` will have a delayed animation
            // Note there is nothing to be animated in this example!
            
        }
        .onChange(of: animatedVariable) { newValue in
            withAnimation(Animation.default.delay(0.25)) {
                delayedAnimatedVariable = newValue
            }
        }
    }
    
}

Question: why in withAnimation(Animation.default.delay(0.25)) you use 0.25 instead of anythings else like 0.5 or 0.3 or whatever?!

Answer: SwiftUI animations usually default to 0.25 seconds of duration, so if you apply the second animation with a 0.25 s delay, it will happen right after the first one. you can of course change that value based on your needs (you also can define duration of your animations, just as a PS, if you didnt know).

Mahdi BM
  • 1,826
  • 13
  • 16
  • This is not ideal. 1) If you set the duration for the animation, you'll always have to remember to change the delay as well. 2) You are creating two state variables just to make it work. Imagine have 3 animation thats needs to be triggered sequentially 1 over the other, then that state variable would exponentially multiply. Although your suggestion could probably work. It is more of a work around rather than a solution. – Archie G. Quiñones Aug 23 '20 at 18:12
  • There is not a direct way to do what you want. this is the best you can get. you can set something like a global variable if you think you might forget. i'll update the answer – Mahdi BM Aug 23 '20 at 18:15
  • on second thoughts, applying `.animation(Animation.linear.delay(0.25))` on your view might work (although it has disadvantages compared to the way i described in the answer). havent tried, but let me know if you had time to try it and it worked out. – Mahdi BM Aug 23 '20 at 18:54
  • I really dont think this is the correct way. This rely too much on the duration of the animation. What will you do with animation where you don't set the duration like say for example a spring animation where only the `damping` is set? – Archie G. Quiñones Aug 24 '20 at 04:33
  • Yes, this not the way it should be, but you either have to do it one of these ways, or not do it at all. i think youre maybe thinking that no way swiftui doesnt have that ability, but as someone who has worked with swiftui from the beginning, i still see many simple things which swiftui doesnt support yet. about spring, there are a few different models of springs, but they are all springs after all. the `spring` animation is the main one, and other springs are just convenience springs to make it easy. you can use a simple spring animation with a fixed `response` time to do that. – Mahdi BM Aug 24 '20 at 06:16
  • you see, there is most of the time a workaround. i feel you are looking for a simpler answer, while i personally dont think it exists. if you want to do it, you can do it, but if you want to do it easily, then i think there is not much of a chance to do it. you can still, of course wait to see if anyone has a better answer to your question – Mahdi BM Aug 24 '20 at 06:19