iOS13+ solution:
This is actually very easy to do using only standard API. Wrap the contents of your sheet into NavigationView and add DragGesture on navigation view using .gesture or .simultaneousGesture. This will cancel-out internal sheet drag gesture. This method is tested and works on all iOS versions iOS13+.
iOS 13+ example:
import SwiftUI
struct SwiftUIView: View {
@State var isPresented = false
var body: some View {
Button("Show") {
isPresented = true
}
.sheet(isPresented: $isPresented) {
NavigationView {
VStack {
Text("Test View")
}
.navigationBarItems(
trailing:
Button {
isPresented = false
} label: {
Image(systemName: "xmark.circle.fill")
.renderingMode(.template)
.foregroundColor(.primary.opacity(0.5))
}
)
}
.gesture(
DragGesture(minimumDistance: 1, coordinateSpace: .local)
)
}
}
}
Modifier to disable interactive dismiss on older systems:
extension View {
@ViewBuilder func interactiveDismissDisabledLegacy(_ isDisabled: Bool = true) -> some View {
if isDisabled {
NavigationView {
self
}
.gesture(
DragGesture(minimumDistance: 1, coordinateSpace: .local)
)
} else {
self
}
}
}
iOS15+ provides new modifier .interactiveDismissDisabled(true), which provides the same functionality. iOS 15+ example:
import SwiftUI
struct SwiftUIView: View {
@State var isPresented = false
var body: some View {
Button("Show") {
isPresented = true
}
.sheet(isPresented: $isPresented) {
VStack {
Text("Test View")
}
.interactiveDismissDisabled(true)
}
}
}