lndbrg
lndbrg

Reputation: 1

Is it possible to present a NavigationStack view from inside a sheet?

Many popular apps have the ability to navigate to a new view from a sheet. For example, in the comment sheets in Instagram and TikTok, pressing on the commenting user's icon pushes in a whole new view for the user's profile. Once that view is dismissed, it returns to the previous view, where the comments sheet is still open.

However, when I have a .navigationDestination outside of the sheet, it does navigate but the sheet remains in place, on top of the views:

.sheet(isPresented: $presentSheet) {
    VStack {
        Button("Present new view") {
            presentDestination = true
        }
    }
}
.navigationDestination(isPresented: $presentDestination) {
    VStack {
        Text("New view")
    }
}

Alternatively if I place the navigationDestination inside the view presented by .sheet, this results in navigation only within the sheet. I would want the whole screen be replaced with the new screen, as usually happens.

Is this not possible with Apple's built-in sheet?

Upvotes: 0

Views: 250

Answers (2)

In the main view you invoke your sheet. Inside the sheetView you Embed the body in a NavigationStack and have your own set of destinations to call.

import SwiftUI
struct ParentView: View {

@State var openSheet = false

  var body: some View {

      Button("Show a sheet") {
          openSheet = true
      }
      .sheet(isPresented: $openSheet) {
          SheetView()
      }
   }
} 
struct SheetView: View {

enum Destination: {
    case view1
    case view2
}

@State private var localRouter: [Destination] = []

  var body: some View {
      NavigationStack(path: $localRouter) {
          destinationView(for: .view1)
              .toolbar {
                  closeButton()
              }
              .navigationDestination(for: Destination.self, destination: { destination in
                  destinationView(for: destination)
                      .toolbar {
                          closeButton()
                      }
              })
      }
  }

  @ViewBuilder
  private func destinationView(for destination: Destination) -> some View {
      switch destination {
          case .view1:
              View1()
          case .view2:
              View2()
      }
   }
}

Upvotes: 0

You could try this approach using a NavigationStack(path: $path) and dismiss() to navigate to a new page of the root view from action/selection in the sheet.

Example code:

struct ContentView: View {
    @State private var presentSheet = false
    @State private var path = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $path){
            Text("ContentView")
            Button("Show Sheet") {
                presentSheet = true
            }
            .navigationDestination(for: String.self) { page in
                if page == "Page1" {
                    VStack {
                        Text("Page1 view")
                    }
                } else {
                    VStack {
                        Text("Page2 view")
                    }
                }
            }
        }
        .sheet(isPresented: $presentSheet) {
            SheetView(path: $path)
        }
    }
}

struct SheetView: View {
    @Environment(\.dismiss) var dismiss
    @Binding var path: NavigationPath
    
    var body: some View {
        VStack {
            Text("SheetView")
            Button("Present Page1 view") {
                path.append("Page1")
                dismiss()
            }
        }
    }
}

Upvotes: 1

Related Questions