I am working on migrating an existing UIKit
+ UIViewController
based app to SwiftUI
.
The UIKit
based implementation creates a stack of different, presented ViewControllers at runtime.
When the user returns to the app using an AppIntent
, e.g. when using a Add item
, this call is passed to the SceneDelegate
which makes sure, the complete stack of presented ViewControllers is dismissed and than presents the AddItemViewController
on the RootVC.
How can the same be done, when switching to SwiftUI views? Is there a similar easy way to dismiss all presented subviews?
Details:
Since the SceneDelegate
knows the RootVC, it can simply call .dismiss(...)
on it. It could use the .presentedViewController
property to walk the presentation stack up to the top and dimiss the VCs from there.
In SwiftUI on the other hand, there are no SubVCs but simply views which are presented as .fullScreenCover
, .sheet
, etc.
Since every view is completely free how its view model is anized, there is not standardized way to check if any sub views are presented or not, is there?
Lets assume the apps root view is container, e.g. like a tab bar, holding different sub views. This root view can not simple call a dismiss
method on all its child views to dismiss any (possibly) presented sub views.
If these are custom views I could adapt the views of course. But what if third party views come into play, where the RootView does not know if sub views are presented or not?
struct TheRootView: View {
@State private var showDetail: Bool = false
var body: some View {
VStack {
Button("Go to Detail") {
showDetail = true
}
.padding()
.fullScreenCover(isPresented: $showDetail) {
ADetailView(showing: $showDetail)
}
ThirPartyView()
}
}
}
struct ADetailView: View {
@State private var showMoreDetails: Bool = false
@Binding var showing: Bool
var body: some View {
VStack {
Button("Show more Details") {
showMoreDetails = true
}
.padding()
.fullScreenCover(isPresented: $showMoreDetails) {
Text("More Details")
Button("Close") {
showMoreDetails = false
}
}
Button("Close") {
showing = false
}
}
}
}
struct ThirPartyView: View {
@State var showCover: Bool = false
var body: some View {
Button("Do something") {
showCover = true
}
.fullScreenCover(isPresented: $showCover) {
Button("Close") {
showCover = false
}
}
}
}
In this example TheRootView
knows when ADetailView
is presented and can simply dismiss it. But it does not know, if ThirPartyView
has presented a sub view.
Is there any way TheRootView
could check this (without changing ThirPartyView
) and dismiss these presented subviews?