Search code examples
swiftuiswiftui-navigationlink

NavigationLInk – Adding a delay before switching to a view


I have this navigation link like this:

NavigationLink(destination: MyForm(item))

I want an animation to perform on the main view, where the navigation link is, before switching to MyForm.

If I do not do that, the animation I want to perform mixes with the animation performed by the NavigationLink itself, as it switch to MyForm and the result is ugly as hell.

I want to add a delay before MyForm loads, after tapping on the navigation link.

Is that possible?


Solution

  • Using a custom container you can retain the same implementation as NavigationLink:

    public struct DelayedNavigationLink<Destination: View, Content: View>: View {
        @State private var activate = false
        private let delay: TimeInterval
        private let content: Content
        private let destination: Destination
        public init(destination: Destination, @ViewBuilder content: () -> Content) {
            self.content = content()
            self.destination = destination
            self.delay = 0
        }
        private init(delay: TimeInterval, destination: Destination, content: Content) {
            self.content = content()
            self.destination = destination
            self.delay = delay
        }
        public var body: some View {
            Button(action: {
                DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
                    activate = true
                }
            }) {
                content
            }.background(
                NavigationLink(destination: destination, isActive: $activate) {
                    Color.clear
                }
            )
        }
        public func delayed(by delay: TimeInterval) -> Self {
            DelayedNavigationLink(delay: delay, destination: destination, content: content)
        }
    }
    

    Example:

    struct Test: View {
        var body: some View {
            DelayedNavigationLink(destination: Text("destination")) {
                Text("Navigate")
            }.delayed(by: 10)
        }
    }