Search code examples
swiftanimationswiftuicancellation

how to stop/cancel withAnimation in SwiftUI


I need to do following. Start a function that will wait 5 seconds and then execute withAnimation block that will last 3 seconds. In this 3 second period value of a variable opacity should get to 0. I should be able to cancel this function anywhere during the 8 seconds. My code is like this:

@State var opacity: Double = 1.0

    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
        withAnimation(.easeInOut(duration: 3)) {
            opacity = 0.0
        }
    }

How can I achieve that this function can be cancellable anytime during the 8 second period. So if the function gets cancelled, opacity gets set to 1.


Solution

  • The solution is to use a DispatchWorkItem like so:

    struct ContentView: View {
        @State var opacity: CGFloat = 1
        @State private var workItem: DispatchWorkItem?
        
        @State var text = 0
        var body: some View {
            VStack {
                
                Text("Opacity")
                    .opacity(opacity)
                
                Button("Start animation") {
                    workItem = DispatchWorkItem {
                        withAnimation(.easeInOut(duration: 3)) {
                            opacity = 0.0
                        }
                    }
                    
                    DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: workItem!)
                }
                
                Button("Cancel Animation") {
                    workItem?.cancel()
                    opacity = 1
                }
                .padding(.top, 20)
                
            }
            .padding()
        }
    }
    

    You can cancel that operation whenever you want but, It's not even needed to accomplish what you want. You could just reset the opacity back to one. It works even without the DispatchWorkItem in my testings, but if you needed a cancellable task, there you have it!