9

I am trying to figure out if there is a way to open a sheet with the new NavigationStack in iOS 16, but can't seem to find a way.

So of cause, it's possible to open a sheet using:

.sheet(isPresented: $isShowing)

But with the new NavigationStack you have an array of a type which you present with:

.navigationDestination(for: SomeType.self, destination: { route in

And it would be awesome if I could somehow define that when a specific destination is presented it opens as a sheet instead of navigating with a modal.

Does anyone know if this is possible to achieve? :)

2 Answers 2

4

I still haven't managed to find a clean solution for this only using navigationDestination, however, I ended up implementing something like this which kind of makes it possible.

I figured I would post it as an answer for now since someone might be able to improve this even further or make it more generic.

enum Route: Hashable, Identifiable {
    var id: Self { return self }
    case details(RouteType)
    case shopping(RouteType)
}

enum RouteType {
    case modal
    case sheet
}

struct ContentView: View {
    @State private var path = NavigationPath()
    @State private var route: Route?
    @State private var sheet: Route?

    func router(_ route: Route, type: RouteType) {
        switch type {
        case .modal:
            path.append(route)
        case .sheet:
            sheet = route
        }
    }

    func getView(for route: Route) -> some View {
        switch route {
        case .details(_):
            return Text("Details View")
        case .shopping(_):
            return Text("Shopping View")
        }
    }

    var body: some View {
        NavigationStack(path: $path) {
            VStack {
                Text("Content View")
                Button("Show View") {
                    route = Route.details(.sheet) // <- Change accordingly
                }
            }
            .navigationTitle("Content View")
            .onChange(of: route) { newRoute in
                guard let newRoute else { return }
                switch newRoute {
                case .details(let type):
                    router(newRoute, type: type)
                case .shopping(let type):
                    router(newRoute, type: type)
                }
                route = nil
            }
            .navigationDestination(for: Route.self) { route in
                getView(for: route)
            }
            .sheet(item: $sheet) { route in
                getView(for: route)
            }
        }
    }
}
0

This worked for me. I can push objects to my route from any view, and load it with a modal sheet.

class Route: ObservableObject {
    
    @Published var presentedObject: [CarObject] = []
    @Published var isPresented: Bool = false

}

struct NavigationWithSheet: View {
    var body: some View {
        
        @EnvironmentObject var route: Route
        
        NavigationStack {
            Button("Open sheet") {
                route.isPresented = true
                route.presentedObject.append(newCar)
            }
            .sheet(isPresented: $route.isPresented) {
                let carObject = route.presentedObject.first
                ViewWithObject(car: carObject!)
            }
        }
        
    }
}

1
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Dec 22, 2022 at 1:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.