Update for iOS 15
根据下面的pawello2222's answer,新的interactiveDismissDisabled(_:)
API现在支持这一点.
struct ContentView: View {
@State private var showSheet = false
var body: some View {
Text("Content View")
.sheet(isPresented: $showSheet) {
Text("Sheet View")
.interactiveDismissDisabled(true)
}
}
}
Pre-iOS-15 answer
我也想这么做,但在任何地方都找不到解决方案.劫持拖动手势的答案是可行的,但当它通过滚动视图或窗体而被取消时,答案就不起作用了.问题中的方法也不太老套,所以我进一步研究了它.
对于我的用例,我有一个表格,理想情况下,当没有内容时,可以将其删除,但当有内容时,必须通过alert 进行确认.
我对这个问题的解决方案是:
struct ModalSheetTest: View {
@State private var showModally = false
@State private var showSheet = false
var body: some View {
Form {
Toggle(isOn: self.$showModally) {
Text("Modal")
}
Button(action: { self.showSheet = true}) {
Text("Show sheet")
}
}
.sheet(isPresented: $showSheet) {
Form {
Button(action: { self.showSheet = false }) {
Text("Hide me")
}
}
.presentation(isModal: self.showModally) {
print("Attempted to dismiss")
}
}
}
}
状态值showModally
确定是否必须以模式显示.如果是这样,将其向下拖动到Disclose只会触发关闭,该关闭只会在示例中打印"Attemed to Disclose",但可用于显示确认解除的alert .
struct ModalView<T: View>: UIViewControllerRepresentable {
let view: T
let isModal: Bool
let onDismissalAttempt: (()->())?
func makeUIViewController(context: Context) -> UIHostingController<T> {
UIHostingController(rootView: view)
}
func updateUIViewController(_ uiViewController: UIHostingController<T>, context: Context) {
context.coordinator.modalView = self
uiViewController.rootView = view
uiViewController.parent?.presentationController?.delegate = context.coordinator
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UIAdaptivePresentationControllerDelegate {
let modalView: ModalView
init(_ modalView: ModalView) {
self.modalView = modalView
}
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
!modalView.isModal
}
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
modalView.onDismissalAttempt?()
}
}
}
extension View {
func presentation(isModal: Bool, onDismissalAttempt: (()->())? = nil) -> some View {
ModalView(view: self, isModal: isModal, onDismissalAttempt: onDismissalAttempt)
}
}
这非常适合我的用例,希望它也能帮助你或其他人.