Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.5k views
in Technique[技术] by (71.8m points)

ios - SwiftUI Dismiss Multiple Modal Sheets

I am using .sheet(isPresented: self.$showModal) in my root view to present a modal. Within the modal, I am using NavigationView to take the user through various pages (for a user profile builder).

In the last page of my navigation stack, I am using @Environment(.presentationMode) var presentationMode and a button which calls self.presentationMode.wrappedValue.dismiss() to dismiss the modal. However, this only dismisses the last page in the navigation stack, and I just end up at the previous page. What I want to do is dismiss the entire navigation stack and end up back at the root view.

Swiping down to dismiss the modal produces the desired result, but I want to do this programatically with the button.

Is this currently possible in SwiftUI, or is this a problem with using NavigationView within a modal sheet?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Solution 1 - Custom EnvironmentKey

A possible solution is to use a custom EnvironmentKey injected to every environment:

struct PresentationKey: EnvironmentKey {
    static let defaultValue: [Binding<Bool>] = []
}

extension EnvironmentValues {
    var presentations: [Binding<Bool>] {
        get { return self[PresentationKey] }
        set { self[PresentationKey] = newValue }
    }
}

Demo:

enter image description here

struct ContentView: View {
    @Environment(.presentations) private var presentations
    @State private var showSheet = false

    var body: some View {
        Button("Show sheet") {
            showSheet = true
        }
        .sheet(isPresented: $showSheet) {
            SheetView()
                .environment(.presentations, presentations + [$showSheet])
        }
    }
}
struct SheetView: View {
    @Environment(.presentations) private var presentations
    @State private var showSheet = false

    var body: some View {
        Button("Show another sheet") {
            showSheet = true
        }
        .sheet(isPresented: $showSheet) {
            SheetNavigationView()
                .environment(.presentations, presentations + [$showSheet])
        }
    }
}
struct SheetNavigationView: View {
    var body: some View {
        NavigationView {
            NavigationLink("Link", destination: SheetNavigationDetailView())
        }
    }
}
struct SheetNavigationDetailView: View {
    @Environment(.presentations) private var presentations

    var body: some View {
        Button("Pop to root") {
            presentations.forEach {
                $0.wrappedValue = false
            }
        }
    }
}

Solution 2 - Dismiss UIKit rootViewController

struct SheetNavigationDetailView: View {

    var body: some View {
        Button("Pop to root") {
            UIApplication.shared.windows.first?.rootViewController?.dismiss(animated: true)
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...