alionthego
alionthego

Reputation: 9703

Can't dismiss modal in SwiftUI

I have been having issues dismissing some modal views in SwiftUI and made the following example to illustrate the problem.

Below we have 4 views. The idea is that the App file will have a switch and decide which view to display based on that Switch's viewForDisplay property.

Initially we display the FirstView which modally presents the SecondView which then modally presents the ThirdView. When the ThirdView sets the viewForDisplay to .fourthView I would expect all the views in the FirstView/SecondView/ThirdView stack to go away and just see the FourthView. However it is showing the SecondView.

enum ViewForDisplay {
    case firstView
    case fourthView
}

class ViewModel: ObservableObject {
    
    @Published var viewForDisplay: ViewForDisplay = .firstView
    
}

@main
struct ModalDismissApp: App {
    
    @ObservedObject var viewModel = ViewModel()
    
    var body: some Scene {
        WindowGroup {
            switch viewModel.viewForDisplay {
            case .firstView:
                FirstView(viewModel: viewModel)
            case .fourthView:
                FourthView()
            }
        }
    }
}

struct FirstView: View {
    
    @State var isPresented: Bool = false
    
    @ObservedObject var viewModel: ViewModel
    
    init(viewModel: ViewModel) {
        self.viewModel = viewModel
    }
    
    var body: some View {
        VStack {
            Text("First View")
            Button(action: {
                isPresented = true
            }, label: {
                Text("Present Second View Modally")
            })
        }
        .fullScreenCover(isPresented: $isPresented, content: {
            SecondView(viewModel: viewModel)
        })
        
    }
}

struct SecondView: View {
    
    @State var isPresented: Bool = false
    
    @ObservedObject var viewModel: ViewModel
    
    init(viewModel: ViewModel) {
        self.viewModel = viewModel
    }
    
    var body: some View {
        VStack {
            Text("Second View")
            Button(action: {
                isPresented = true
            }, label: {
                Text("Present Third View Modally")
            })
        }
        .fullScreenCover(isPresented: $isPresented, content: {
            ThirdView(viewModel: viewModel)
        })
    }
}

struct ThirdView: View {
    
    @ObservedObject var viewModel: ViewModel
    
    init(viewModel: ViewModel) {
        self.viewModel = viewModel
    }
    
    var body: some View {
        VStack {
            Text("Third View")
            Button(action: {
                viewModel.viewForDisplay = .fourthView
            }, label: {
                Text("Dismiss Modals and go to Fourth View")
            })
        }
    }
}

struct FourthView: View {
    var body: some View {
        Text("Fourth View")
    }
}

This only happens when two levels of modal are applied. For example, if I were to set the viewForDisplay to .fourthView from the SecondView everything works fine. But for some reason when I have more than one modal it doesn't work.

I can work around this by dismissing the ThirdView and then setting the .viewForDisplay property but that gives me an undesirable animation. I just want to go directly to my FourthView and not sure why with multiple modals this is an issue.

enter image description here

Upvotes: 0

Views: 416

Answers (1)

Raja Kishan
Raja Kishan

Reputation: 18904

You first need to dismiss all the presented controllers and then switch to the fourth view.

Here is the easy possible solution.

In the 3rd view, before switching to the fourth view, just dismiss all views.

struct ThirdView: View {
    
    @ObservedObject var viewModel: ViewModel
    
    init(viewModel: ViewModel) {
        self.viewModel = viewModel
    }
    
    var body: some View {
        VStack {
            Text("Third View")
            Button(action: {
                UIApplication.shared.windows.first?.rootViewController?.dismiss(animated: true, completion: {
                    
                }) //<-- Dismisss all view
                viewModel.viewForDisplay = .fourthView
            }, label: {
                Text("Dismiss Modals and go to Fourth View")
            })
        }
    }
}

Upvotes: 1

Related Questions