Prevent dismissal of modal view controller in Swif

2020-02-19 10:59发布

问题:

At WWDC 2019, Apple announced a new "card-style" look for modal presentations, which brought along with it built-in gestures for dismissing modal view controllers by swiping down on the card. They also introduced the new isModalInPresentation property on UIViewController so that you can disallow this dismissal behavior if you so choose.

So far, though, I have found no way to emulate this behavior in SwiftUI. Using the .presentation(_ modal: Modal?), does not, as far as I can tell, allow you to disable the dismissal gestures in the same way. I also attempted putting the modal view controller inside a UIViewControllerRepresentable View, but that didn't seem to help either:

struct MyViewControllerView: UIViewControllerRepresentable {
    func makeUIViewController(context: UIViewControllerRepresentableContext<MyViewControllerView>) -> UIHostingController<MyView> {
        return UIHostingController(rootView: MyView())
    }

    func updateUIViewController(_ uiViewController: UIHostingController<MyView>, context: UIViewControllerRepresentableContext<MyViewControllerView>) {
        uiViewController.isModalInPresentation = true
    }
}

Even after presenting with .presentation(Modal(MyViewControllerView())) I was able to swipe down to dismiss the view. Is there currently any way to do this with existing SwiftUI constructs?

回答1:

By changing the gesture priority of any view you don't want to be dragged, you can prevent DragGesture on any view. For example for Modal it can be done as bellow:

Maybe it is not a best practice, but it works perfectly

struct ContentView: View {

@State var showModal = true

var body: some View {

    Button(action: {
        self.showModal.toggle()

    }) {
        Text("Show Modal")
    }.sheet(isPresented: self.$showModal) {
        ModalView()
    }
  }
}

struct ModalView : View {
@Environment(\.presentationMode) var presentationMode

let dg = DragGesture()

var body: some View {

    ZStack {
        Rectangle()
            .fill(Color.white)
            .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
            .highPriorityGesture(dg)

        Button("Dismiss Modal") {
            self.presentationMode.wrappedValue.dismiss()
        }
    }
  }
}