SwiftUI使用户不能下滑关闭Sheet
在某些情况下,我们不能直接让用户自主关闭sheet,比如说登陆界面等
Full Screen
SwiftUI提供一种全新的Sheet(请在Xcode12中尝试),让你以全屏的方式弹出sheet而不是卡片,这种方式下如果不提供关闭按钮,则用户无法自主关闭。
struct FullScreenCoverPresentedOnDismiss: View {
@State private var isPresenting = false
var body: some View {
Button("Present Full-Screen Cover") {
isPresenting.toggle()
}
.fullScreenCover(isPresented: $isPresenting,
onDismiss: didDismiss) {
VStack {
Text("A full-screen modal view.")
.font(.title)
Text("Tap to Dismiss")
}
.onTapGesture {
isPresenting.toggle()
}
.foregroundColor(.white)
.frame(maxWidth: .infinity,
maxHeight: .infinity)
.background(Color.blue)
.ignoresSafeArea(edges: .all)
}
}
func didDismiss() {
// Handle the dismissing action.
}
}

这种方式固然不错,但是这有点不美观(至少我是这么认为的),并且似乎不像2021的东西。
Sheet
在UIKit当中我们可以轻松控制用户是否可以滑动关闭试图,由于SwiftUI还不太成熟所以这功能没有,但是我们可以通过构建UIkit桥梁完成。
首先加入以下代码
struct MbModalHackView: UIViewControllerRepresentable {
var dismissable: () -> Bool = { false }
func makeUIViewController(context: UIViewControllerRepresentableContext<MbModalHackView>) -> UIViewController {
MbModalViewController(dismissable: self.dismissable)
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}
}
extension MbModalHackView {
private final class MbModalViewController: UIViewController, UIAdaptivePresentationControllerDelegate {
let dismissable: () -> Bool
init(dismissable: @escaping () -> Bool) {
self.dismissable = dismissable
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func didMove(toParent parent: UIViewController?) {
super.didMove(toParent: parent)
setup()
}
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
dismissable()
}
// set delegate to the presentation of the root parent
private func setup() {
guard let rootPresentationViewController = self.rootParent.presentationController, rootPresentationViewController.delegate == nil else { return }
rootPresentationViewController.delegate = self
}
}
}
extension UIViewController {
fileprivate var rootParent: UIViewController {
if let parent = self.parent {
return parent.rootParent
}
else {
return self
}
}
}
extension View {
/// Control if allow to dismiss the sheet by the user actions
public func allowAutoDismiss(_ dismissable: @escaping () -> Bool) -> some View {
self
.background(MbModalHackView(dismissable: dismissable))
}
/// Control if allow to dismiss the sheet by the user actions
public func allowAutoDismiss(_ dismissable: Bool) -> some View {
self
.background(MbModalHackView(dismissable: { dismissable }))
}
}
添加这些代码后在sheet上做一些修改
.sheet(isPresented: self.$showGuide, content: {
GuidePageView(canHidGuide: self.$canHidGuide, hand: self.$hand)
.allowAutoDismiss { self.canHidGuide }
})
注意,我们添加了一个.allowAutoDismiss { self.canHidGuide }
这个需要传入一个Bool类型变量,代表是否支持用户直接下拉关闭Sheet,你可以传入一个State变量控制这个参数。