Is it possible to make a modal non-dismissible in SwiftUI?

This is a common problem and a "code smell"... well not really code but a "design pattern smell" anyway.

The problem is that you are making your login process part of the rest of the app.

Instead of presenting the LoginRegister over the App you should really be showing either App or LoginRegister.

i.e. you should have some state object like userLoggedIn: Bool or something and depending on that value you should show either App or LoginRegister.

Just don't have both in the view hierarchy at the same time. That way your user won't be able to dismiss the view.


iOS 15 and later:

Use .interactiveDismissDisabled(true) on the sheet, that's all.

Prev iOS 15:

You can try to do this by using a highPriorityGesture. Of course the blue Rectangle is only for demonstration but you would have to use a view which is covering the whole screen.

struct ModalViewNoClose : View {
    @Environment(\.presentationMode) var presentationMode
    
    let gesture = DragGesture()
    
    var body: some View {
        
        Rectangle()
            .fill(Color.blue)
            .frame(width: 300, height: 600)
            .highPriorityGesture(gesture)
            
            .overlay(
                VStack{
                    Button("Close") {
                        self.presentationMode.value.dismiss()
                    }.accentColor(.white)
                    Text("Modal")
                        .highPriorityGesture(gesture)
                    TextField("as", text: .constant("sdf"))
                        .highPriorityGesture(gesture)
                } .highPriorityGesture(gesture)
        )
            .border(Color.green)
    }
}

If you dont mind using Introspect:

import Introspect

@available(iOS 13, *)
extension View {
    /// A Boolean value indicating whether the view controller enforces a modal behavior.
    ///
    /// The default value of this property is `false`. When you set it to `true`, UIKit ignores events
    /// outside the view controller's bounds and prevents the interactive dismissal of the
    /// view controller while it is onscreen.
    public func isModalInPresentation(_ value: Bool) -> some View {
        introspectViewController {
            $0.isModalInPresentation = value
        }
    }
}

Usage:

.sheet {
    VStack {
        ...
    }.isModalInPresentation(true)
}

Tags:

Swiftui