Prevent dismissal of sheet in SwiftUI

I'd like to emulate the behavior of UIViewController.isModalInPresentation in SwiftUI. In my first attempt, I defined the following view:

Code Block
struct ModalView<Content: View>: UIViewControllerRepresentable {
var content: () -> Content
func makeUIViewController(context: Context) -> UIHostingController<Content> {
let controller = UIHostingController(rootView: content())
controller.isModalInPresentation = true
return controller
}
func updateUIViewController(_ imagePickerController: UIHostingController<Content>, context: Context) {}
}


From my main app view, I then present the ModalView as a sheet:

Code Block
struct ContentView: View {
@State
var presentSheet: Bool = true
var body: some View {
Text("Hello, world!")
.sheet(isPresented: $presentSheet) {
ModalView {
Text("Sheet")
}
}
}
}


But the user is still able to dismiss the ModalView by swiping down. I would expect this sheet to be non-dismissible. Is anything like this supposed to work? If not, is there some other way to prevent the dismissal of a sheet in SwiftUI?

The closest workaround I've found is to apply .highPriorityGesture(DragGesture()) to the content of the sheet, but swiping down with two fingers still works.

Accepted Reply

FWIW, my question from last year on Stack Overflow received an answer that appears to properly implement this behavior by dipping down into the presentationController from a UIViewControllerRepresentable view. It's more verbose than ideal, but it's reusable!

My ideal API for this would be one of a few things:
  • Another argument isModal passed to the .sheet modifier.

  • A modifier like the Stack Overflow answer enables

  • Behavior is automatically enabled if I call .sheet(isPresented: .constant(shouldPresentSheet).

Replies

I was hoping the new updates to SwiftUI would allow us to do this but the fact that we still can't is immensely disappointing.
Same. I’ve been looking for a way to do this since last year, so I’m resurfacing this question in case there’s a hidden setting somewhere that enables this behavior!
FWIW, my question from last year on Stack Overflow received an answer that appears to properly implement this behavior by dipping down into the presentationController from a UIViewControllerRepresentable view. It's more verbose than ideal, but it's reusable!

My ideal API for this would be one of a few things:
  • Another argument isModal passed to the .sheet modifier.

  • A modifier like the Stack Overflow answer enables

  • Behavior is automatically enabled if I call .sheet(isPresented: .constant(shouldPresentSheet).

I have created a extension to prevent auto dismiss very easily, just call the way like:


.sheet(isPresented: $presenting) {
ModalContent()
.allowAutoDismiss { false }
}


The code
https://gist.github.com/mobilinked/9b6086b3760bcf1e5432932dad0813c0

In case anyone comes across this, there is now a method called interactiveDismissDisabled found here: https://developer.apple.com/documentation/swiftui/view/interactivedismissdisabled(_:)

Put the modifier on the view that is being presented in the sheet, and the user will not be able to swipe to dismiss.

Ex:

 .sheet(isPresented: $isPresented) {
            Text("test")
                .interactiveDismissDisabled()
        }