matteopuc / swiftui-navigation-stack

An alternative SwiftUI NavigationView implementing classic stack-based navigation giving also some more control on animations and programmatic navigation.
MIT License
930 stars 87 forks source link

sheets stop showing #23

Closed valexa closed 4 years ago

valexa commented 4 years ago

after changing the parent of a view from NavigationView to NavigationStackView sheets no longer work inside its children eg:

struct ChildView: View {
    @State var showPopup = false
    var body: some View {
        Text("test")
            .onTapGesture { self.showPopup = true }
            .onAppear { self.showPopup = true }
            .sheet(isPresented: self.$showPopup) { Text("popup") }
    }
}

popup is never shown, if I revert back to NavigationView it works fine.

matteopuc commented 4 years ago

Hi @valexa. The problem is related to the onAppear. The child onAppear is called immediately as soon as the transition animation starts (and not when the transition animation ends). See this other linked issue https://github.com/biobeats/swiftui-navigation-stack/issues/19 basically you are showing the sheet during a transition and this breaks the sheet somehow. Take a look at this snippet here below without the onAppear (I've just added some colours to better see the difference between the pages). Everything it works as expected:

import SwiftUI
import NavigationStack

struct Root: View {
    var body: some View {
        NavigationStackView {
            ZStack {
                Color.green.edgesIgnoringSafeArea(.all)
                PushView(destination: ChildView()) {
                    Text("PUSH")
                }
            }
        }
    }
}

struct ChildView: View {
    @State var showPopup = false
    var body: some View {
        ZStack {
            Color.yellow.edgesIgnoringSafeArea(.all)
            Text("test")
                .onTapGesture { self.showPopup = true }
                .sheet(isPresented: self.$showPopup) { Text("popup") }
        }
    }
}

struct Transition_Previews: PreviewProvider {
    static var previews: some View {
        Root()
    }
}

The result is:

Jul-02-2020 10-42-04

At the moment, unfortunately, the only workaround to show the sheet onAppear is something like (I've just modified the ChildView):

struct ChildView: View {
    private let transitionDuration = 0.2 //<-- this is the default transition duration for the navigation stack
    @State var showPopup = false
    var body: some View {
        ZStack {
            Color.yellow.edgesIgnoringSafeArea(.all)
            Text("test")
                .onTapGesture { self.showPopup = true }
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now()+self.transitionDuration) { //<-- dispatch after here
                        self.showPopup = true
                    }
                }
                .sheet(isPresented: self.$showPopup) { Text("popup") }
        }
    }
}

You'll get this:

Jul-02-2020 10-50-59

Or, if you specify a custom transition for your navigation stack:

import SwiftUI
import NavigationStack

struct Root: View {
    private let transitionDuration = 2.0 //<-- custom transition duration
    var body: some View {
        NavigationStackView(transitionType: .custom(AnyTransition.opacity), easing: .easeOut(duration: transitionDuration)) { //<-- custom transition
            ZStack {
                Color.green.edgesIgnoringSafeArea(.all)
                PushView(destination: ChildView(transitionDuration: transitionDuration)) {
                    Text("PUSH")
                }
            }
        }
    }
}

struct ChildView: View {
    let transitionDuration: Double
    @State var showPopup = false
    var body: some View {
        ZStack {
            Color.yellow.edgesIgnoringSafeArea(.all)
            Text("test")
                .onTapGesture { self.showPopup = true }
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now()+self.transitionDuration) {
                        self.showPopup = true
                    }
                }
                .sheet(isPresented: self.$showPopup) { Text("popup") }
        }
    }
}

struct Transition_Previews: PreviewProvider {
    static var previews: some View {
        Root()
    }
}

Jul-02-2020 10-54-39

valexa commented 4 years ago

That did the trick, thanks