Disable the interactive dismissal of presented view controller
Asked Answered
F

8

225

iOS 13 introduces a new design of modalPresentationStyle .pageSheet (and its sibling .formSheet) for modally presented view controllers…

The new sliding modal presentation in iOS 13

…and we can dismiss these sheets by sliding the presented view controller down (interactive dismissal). Although the new "pull-to-dismiss" feature is pretty useful, it may not always be desirable.

THE QUESTION: How can we turn the interactive dismissal off? - Bear in mind we keep the presentation style the same.

Flasket answered 5/6, 2019 at 11:11 Comment(2)
Possible duplicate of Presenting modal in iOS 13 fullscreenLilialiliaceous
@MehulThakkar That's a different question.Vinous
F
439

Option 1:

viewController.isModalInPresentation = true

Disabled interactive dismissal

(Disabled interactive .pageSheet dismissal acts like this.)

  • Since the iOS 13, UIViewController contains a new property called isModalInPresentation which must be set to true to prevent the interactive dismissal.
  • It basically ignores events outside the view controller's bounds. Bear that in mind if you are using not only the automatic style but also presentation styles like .popover etc.
  • This property is false by default.

From the official docs: If true, UIKit ignores events outside the view controller's bounds and prevents the interactive dismissal of the view controller while it is onscreen.


Option 2:

func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
    return false
}
  • Since the iOS 13, UIAdaptivePresentationControllerDelegate contains a new method called presentationControllerShouldDismiss.
  • This method is called only if the presented view controller is not dismissed programmatically and its isModalInPresentation property is set to false.

Tip: Don't forget to assign presentationController's delegate. But be aware, it is known that even just accessing the presentationController can cause a memory leak.

Flasket answered 5/6, 2019 at 11:11 Comment(7)
If the presented view controller is a navigation controller, you can either set isModalInPresentation on the navigation controller or on the individual view controllers shown in the navigation stack. The latter allows you to choose on a screen-by-screen basis whether the interactive dismissal is possible. Careful with search controllers, they take precedence over the individual view controller (but not the navigation controller). More info in my blog post: medium.com/@hacknicity/…Swagman
Keep in mind that if your VC is presented as a popover, this will prevent the popover from being dismissed when tapping outside of itZofiazoha
Objective-C: viewController.modalInPresentation = YES;Bozo
Anyone got this to work when setting this flag on a UIImagePickerController? For us it looks like the UIImagePickerController is ignoring it and so it can be dismissed with the swipe gesture. Maybe it's an iOS 13 bug.Zofiazoha
developer.apple.com/documentation/uikit/view_controllers/…Rascality
When presentationControllerShouldDismiss(_ presentationController: UIPresentationController) returns false, presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) is called so you can do things like add a confirmation dialogue if the user has entered data.Sculpin
I'm also seeing issues when using a UIImagePickerController, presentationControllerShouldDismiss is ignored but other delegate functions such as presentationControllerWillDismiss are called.Worship
S
91
  1. If you want the same behaviour as it's in previous iOS version (< iOS13) like model presentation in fullscreen, just set the presentation style of your destination view controller to UIModalPresentationStyle.fullScreen

    let someViewController = \*VIEW CONTROLLER*\
    someViewController.modalPresentationStyle = .fullScreen
    

    And if you are using storyboard just select the segua and select Full Screen form the Presentation dropdown.

    enter image description here

  2. If you just want to disable the interactive dismissal and keep the new presentation style set UIViewController property isModalInPresentation to true.

    if #available(iOS 13.0, *) {
        someViewController.isModalInPresentation = true // available in IOS13
    }
    
Sauls answered 6/6, 2019 at 22:45 Comment(2)
It works better than using {controller.isModalInPresentation = true }.Hilarius
Does second approach work with previous iOS version? < iOS13.0Misfire
B
12

The property isModalInPresentation might help.

From the documentation:

When you set it to true, UIKit ignores events outside the view controller's bounds and prevents the interactive dismissal of the view controller while it is onscreen.

You can use it like this:

let controller = MyViewController()
controller.isModalInPresentation = true
self.present(controller, animated: true, completion: nil)
Bernita answered 25/9, 2019 at 10:28 Comment(0)
U
10

If you have some business logic, something like all fields should be filled before dismissing, you should:

On ViewDidLoad if your ViewController has been presented within a Navigation Controller:

func viewDidLoad() { 
    self.navigationController?.presentationController?.delegate = self
}

If not, simply use

func viewDidLoad() { 
    self.presentationController?.delegate = self
}

Then implement the delegate method:

extension ViewController: UIAdaptivePresentationControllerDelegate {

    func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
        guard let text = firstName.text, text.isEmpty else { return false }
        guard let text = lastName.text, text.isEmpty else { return false }
        ...
    
        return true
    }

}
Unscathed answered 25/5, 2021 at 18:49 Comment(0)
B
5

If you are using storyboards to layout your UI I have found the best way to disable this interactive dismissal when using a navigation controller is to change the presentation of the Navigation Controller in the attribute inspector from Automatic to Full Screen. All view controllers in your navigation stack will then be full screen and will not be able to be dismissed by the user.

Attribute Inspector showing presentation option for the navigation controller

Bosporus answered 11/10, 2019 at 12:43 Comment(0)
A
1

Apple shared a sample code about it at this link

It uses isModalInPresentation as many users suggestion.

Assembler answered 11/12, 2019 at 12:22 Comment(0)
D
0

i was try to so hard for solve this problem but the solution are work for me is i select ViewController in **mainstoryboard > inspector > presentation > Full Screen ** default Automatic to change FullScreen

it's work for me

Deutsch answered 11/9, 2023 at 4:31 Comment(1)
Please do not post duplicate answers.Durnan
P
-2

All solutions are good, but in my case, I need an option to stop movement. So this is a code for that.

if you want to block movement:

self.yourViewController?.presentedView?.gestureRecognizers?[0].isEnabled = false

And if you want to unblock movement:

self.yourViewController?.presentedView?.gestureRecognizers?[0].isEnabled = true
Penurious answered 7/9, 2021 at 8:11 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.