Here is the full functional example of nested modals closed on the last screen ( number #3 ) from the Close button for someone who might need it.
So below we have the main screen where we initiate and trigger modal:
struct OnboardingFlowModal: View {
@State private var showOnboardingFlow: Bool = false
var body: some View {
VStack(spacing: 50){
Text("content of main screen".capitalized)
Spacer()
Button {
showOnboardingFlow.toggle()
} label: {
Text("Start Onboarding")
}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.roundedRectangle(radius: 12))
.controlSize(.large)
.padding()
}
.sheet(isPresented: $showOnboardingFlow,
onDismiss: didDismiss) {
ScreenOne(showOnboardingFlow: $showOnboardingFlow)
}
}
func didDismiss(){
//dismiss function here
}
}
Screen #1, which starts the navigation flow for the modal screens:
struct ScreenOne: View {
@Binding var showOnboardingFlow: Bool
var body: some View{
NavigationView {
VStack{
Text("Welcome to screen #1".capitalized)
}
.navigationTitle("Screen #1")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink {
ScreenTwo(showOnboardingFlow: $showOnboardingFlow)
} label: {
Text("Next")
}
}
}
}
}
}
Screen #2 for illustrative purposes, where we have the button towards the last modal in the navigation:
struct ScreenTwo: View {
@Binding var showOnboardingFlow: Bool
var body: some View{
VStack{
Text("Welcome to screen #2".capitalized)
}
.navigationTitle("Screen #2")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink {
ScreenThree(showOnboardingFlow: $showOnboardingFlow)
} label: {
Text("Next")
}
}
}
}
}
Screen #3, where the Close button is displayed and it closes all of the nested modals:
struct ScreenThree: View {
@Binding var showOnboardingFlow: Bool
var body: some View{
VStack{
Text("Welcome to screen #3".capitalized)
}
.navigationTitle("Screen #3")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
showOnboardingFlow = false
} label: {
Text("Close")
}
}
}
}
}