5

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? :)

bjorn.lau
  • 774
  • 5
  • 16

2 Answers2

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!)
            }
        }
        
    }
}

Andersen
  • 21
  • 3
  • 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](/help/how-to-answer). – Community Dec 22 '22 at 01:08
0

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)
            }
        }
    }
}
bjorn.lau
  • 774
  • 5
  • 16