I have stacked multiple view via NavigationLink within a list. My app code is complex, so I have tried to simplify it as much as I could.
Let’s say I have a button “Click Me” in one of the main view’s (to keep things simple, I have kept it in ContentView in my sample code) which when clicked opens a sheet. This sheet has a navigation stack and navigates to 3 different views.
Last view (named as “ThirdListView”) has 2 buttons – Done and Reset. When Done button is tapped, I want to close all the views and dismiss the sheet and get back to Main view (Content View in this case). When Reset button is tapped, I want to get to the first view in the sheet.
Here is how the hierarchy of my code is:
Content View -> Opens a sheet called as MediatorView -> Opens FirstListView within same sheet -> Opens SecondListView within same sheet -> Opens ThirdListView within same sheet.
Here is what I am trying to achieve:
Tap Reset on ThirdListView, app should navigate back to MediatorView
Tap Done on ThirdListView, app should navigate back to ContentView
Code:
import SwiftUI
import Foundation
struct ContentView: View {
@State var openMediatorView: Bool = false
var body: some View {
VStack {
Button {
self.openMediatorView.toggle()
} label: {
Text("Click Me").font(.body.bold())
}
}
.sheet(isPresented: self.$openMediatorView) {
MediatorView()
}
}
}
struct MediatorView: View {
let firstList: [String] = ["One", "Two", "Three", "Four", "Five"]
let secondList: [String] = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"]
let thirdList: [String] = ["One", "Two", "Three", "Four", "Five", "Six", "Seven"]
@State var showFirstRow: Bool = false
var body: some View {
NavigationStack {
Group {
if firstList.count > 1 {
FirstListView(isHidden: .constant(true), shortList: firstList, longList: secondList, thirdList: thirdList)
} else {
SecondListView(isHidden: .constant(true), longList: secondList, thirdList: thirdList).navigationBarBackButtonHidden()
}
}
.interactiveDismissDisabled()
}
}
}
struct FirstListView: View {
init(isHidden: Binding<Bool>, shortList: [String], longList: [String], thirdList: [String]) {
self.isHidden = isHidden
self.shortList = shortList
self.longList = longList
self.thirdList = thirdList
}
var isHidden: Binding<Bool>
var shortList: [String]
var longList: [String]
var thirdList: [String]
var body: some View {
ScrollViewReader { proxy in
VStack {
List(shortList, id: \.hashValue) { value in
NavigationLink(destination: {
SecondListView(isHidden: .constant(true), longList: longList, thirdList: thirdList)
},
label: {
HStack {
Text(value)
Spacer()
}
.contentShape(Rectangle())
})
}
.listStyle(.plain)
.contentShape(Rectangle())
}
}
.navigationTitle("First List")
.interactiveDismissDisabled()
}
}
struct SecondListView: View {
init(isHidden: Binding<Bool>, longList: [String], thirdList: [String]) {
self.isHidden = isHidden
self.longList = longList
self.thirdList = thirdList
}
var isHidden: Binding<Bool>
var longList: [String]
var thirdList: [String]
var body: some View {
ScrollViewReader { proxy in
VStack {
List(longList, id: \.hashValue) { value in
NavigationLink(destination: {
ThirdListView(isHidden: .constant(true), thirdList: thirdList)
},
label: {
HStack {
Text(value)
Spacer()
}
.contentShape(Rectangle())
})
}
.listStyle(.plain)
.contentShape(Rectangle())
}
}
.navigationTitle("Second List")
.interactiveDismissDisabled()
}
}
struct ThirdListView: View {
@Environment(\.presentationMode) private var presentationMode
init(isHidden: Binding<Bool>, thirdList: [String]) {
self.isHidden = isHidden
self.thirdList = thirdList
}
var isHidden: Binding<Bool>
var thirdList: [String]
var body: some View {
ScrollViewReader { proxy in
VStack {
List(thirdList, id: \.hashValue) { value in
HStack {
Text(value)
Spacer()
}
.contentShape(Rectangle())
}
.listStyle(.plain)
.contentShape(Rectangle())
// TODO: Tapping this should navigate this view back to Mediator View i.e. first view in the sheet.
Button {
isHidden.wrappedValue = false
presentationMode.wrappedValue.dismiss()
} label: {
Text("Reset to Mediator View").font(.body.bold())
}
}
}
.interactiveDismissDisabled()
.navigationTitle("Third List")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
// TODO: Tapping this should navigate this view back to Content View i.e. close the sheet completely.
Button {
isHidden.wrappedValue = false
presentationMode.wrappedValue.dismiss()
} label: {
Text("Done").font(.body.bold())
}
}
}
}
}




