1

How can i get the Y offset of a a moving element at the same time while it's moving?

This is the code that I'm tring the run:

import SwiftUI

struct testView: View {
    @State var showPopup: Bool = false
    
    var body: some View {
        ZStack {
            VStack {
                Button(action: {
                    self.showPopup.toggle()
                }) {
                    Text("show popup")
                }
                
                
                Color.black
                    .frame(width: 200, height: 200)
                    .offset(y: showPopup ? 0 : UIScreen.main.bounds.height)
                    .animation(.easeInOut)
                
            }
        }
    }
}

struct testView_Previews: PreviewProvider {
    static var previews: some View {
        testView()
    }
}

I want to get the Y value of the black squar when the button is clicked the squar will move to a 0 position however I want to detect when the squar did reach the 0 value how can i do that?

Cod3rMax
  • 878
  • 3
  • 18
  • You need your AnimatableModifier, then you can intercept changed value in animatableData. Like in https://stackoverflow.com/a/61017784/12299030. – Asperi Nov 24 '20 at 04:56

2 Answers2

0

SwiftUI doesn't provide a callback with an animation completion, so there are two methods to accomplish detecting when the square has finished animating.

Method 1: Using AnimatableModifier. Here's a well-written Stack Overflow post on how to set that up.

Method 2: Using a Timer to run after the animation has completed. The idea here is to create a scheduled timer that runs after the timer has finished.

struct ContentView: View {
    @State var showPopup: Bool = false
    
    var body: some View {
        ZStack {
            VStack {
                Button(action: {
                    // add addition here with specified duration
                    withAnimation(.easeInOut(duration: 1), {
                        self.showPopup.toggle()
                    })

                    // set timer to run after the animation's specified duration
                    _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { timer in
                        // run your completion code here eg.
                        withAnimation(.easeInOut(duration: 1)) {
                            self.showPopup.toggle()
                        }
                        timer.invalidate()
                    }
                }) {
                    Text("show popup")
                }
                
                Color.black
                    .frame(width: 200, height: 200)
                    .offset(y: showPopup ? 0 : UIScreen.main.bounds.height)
            }
        }
    }
}
rohanphadte
  • 978
  • 6
  • 19
0

Default animation duration (for those animations which do not have explicit duration parameter) is usually 0.25-0.35 (independently of where it is started & platform), so in your case it is completely safe (tested with Xcode 11.4 / iOS 13.4) to use the following approach:

withAnimation(.spring()){
    self.offset = .zero
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        self.animationRunning = false
    }
}