ios – Dismissing multiple views within navigation stack


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

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img