42

(Xcode6, iOS8, Swift, iPad)

I am trying to create a classic Web-like modal view, where the outside of the dialog box is "grayed-out." To accomplish this, I've set the alpha value of the backgroundColor of the view for the modal to 0.5, like so:

self.view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5)

The only problem is that when the modal becomes full-screen, the presenting view is removed. (Ref Transparent Modal View on Navigation Controller).

(A bit irritated at the concept here. Why remove the underlying view? A modal is, by definition, to appear atop other content. Once the underlying view is removed, it's not really a modal anymore. it's somewhere between a modal and a push transition. Wa wa wa... Anyway..)

To prevent this from happening, I've set the modalPresentationStyle to CurrentContext in the viewDidLoad method of the parent controller, and in Storyboard... but no luck.

    self.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
    self.navigationController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext

How do I prevent the presenting view from being removed when the modal becomes full screen?

tyvm.. more info below.

Also in Storyboard, like so (Presentation: Current Context)

enter image description here

Thx for your help... documentation below:

enter image description here

Community
  • 1
  • 1
kmiklas
  • 13,085
  • 22
  • 67
  • 103

7 Answers7

48

First, remove all explicit setting of modal presentation style in code and do the following:

  1. In the storyboard set the ModalViewController's modalPresentation style to Over Current context

img1

  1. Check the checkboxes in the Root/Presenting ViewController - Provide Context and Define Context. They seem to be working even unchecked.
Riskov
  • 844
  • 7
  • 12
  • 2
    This did not work UNTIL I "removed all explicit setting of modal presentation style" - which means if you have something like "vc.modalPresentationStyle = UIModalPresentationStyle.CurrentContext", you need to remove that code before the storyboard instructions will have an effect. – Scott Weinert Sep 04 '14 at 17:28
  • Was your app a Universal app or an iPhone only app? Does this only work with Universal apps? – Crashalot Jan 28 '16 at 03:11
  • 3
    Thank you very much, checking "Provide Context" and "Define Context" on the presenting VC made it work. I guess the storyboard sometimes defines your view controller as the "providing context" automatically, sometimes not, depending on how your view hierarchy is organized. – Alexandre G. Mar 11 '16 at 08:41
  • 1
    Beautiful answer. Exactly what I needed, didnt want to set this stuff on prepareforsegue, now I can invoke performsegue and the viewcontroller is all set up, thanks – Gustavo Baiocchi Costa Mar 24 '17 at 14:09
  • This solution isn't working for me. Maybe its because my modal view controller is embedded in a Navigation Controller? Some help would be great! – user7097242 Feb 10 '18 at 01:29
24

You can try this code for Swift:

let popup : PopupVC = self.storyboard?.instantiateViewControllerWithIdentifier("PopupVC") as! PopupVC
let navigationController = UINavigationController(rootViewController: popup)
navigationController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.presentViewController(navigationController, animated: true, completion: nil)

For swift 4 latest syntax using extension:

extension UIViewController {
    func presentOnRoot(`with` viewController : UIViewController){
        let navigationController = UINavigationController(rootViewController: viewController)
        navigationController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        self.present(navigationController, animated: false, completion: nil)
    }
}

How to use:

let popup : PopupVC = self.storyboard?.instantiateViewControllerWithIdentifier("PopupVC") as! PopupVC
self.presentOnRoot(with: popup)
ZGski
  • 2,398
  • 1
  • 21
  • 34
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
  • 1
    This works! Can you please tell me how it works using UINavigationController and why it doesn't work without using UINavigationController? – Anirudha Mahale Jun 02 '17 at 10:16
  • @Anirudha Mahale: To work without Navigation controller you need to do something like this: let popup : StickerCollectionVC = self.storyboard?.instantiateViewController(withIdentifier: "StickerCollectionVC") as! StickerCollectionVC popup.stickerCollectionVCDelegate = self popup.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext self.present(popup, animated: true, completion: nil) – Swifty Codes Aug 22 '17 at 11:17
14

This worked for me in Swift 5.0. Set the Storyboard Id in the identity inspector as "destinationVC".

@IBAction func buttonTapped(_ sender: Any) {
    let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
    let destVC = storyboard.instantiateViewController(withIdentifier: "destinationVC") as! MyViewController

    destVC.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
    destVC.modalTransitionStyle = UIModalTransitionStyle.crossDissolve

    self.present(destVC, animated: true, completion: nil)
}
AceRam
  • 279
  • 3
  • 6
13

The only problem I can see in your code is that you are using CurrentContext instead of OverCurrentContext.

So, replace this:

self.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext

for this:

self.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
Ivens Denner
  • 523
  • 5
  • 12
2

The problem with setting the modalPresentationStyle from code was that you should have set it in the init() method of the presented view controller, not the parent view controller.

From UIKit docs: "Defines the transition style that will be used for this view controller when it is presented modally. Set this property on the view controller to be presented, not the presenter. Defaults to UIModalTransitionStyleCoverVertical."

The viewDidLoad method will only be called after you already presented the view controller.

The second problem was that you should use UIModalPresentationStyle.overCurrentContext.

  • 1
    This helped me out, thanks! I was trying to set the style in the viewDidLoad but it was happening too late but throwing it in the init did it – Kdawgwilk Apr 13 '18 at 22:10
2

The only way I able to get this to work was by doing this on the presenting view controller:

    func didTapButton() {
    self.definesPresentationContext = true
    self.modalTransitionStyle = .crossDissolve
    let yourVC = self.storyboard?.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
    let navController = UINavigationController(rootViewController: yourVC)
    navController.modalPresentationStyle = .overCurrentContext
    navController.modalTransitionStyle = .crossDissolve
    self.present(navController, animated: true, completion: nil)
}
user7097242
  • 1,034
  • 3
  • 16
  • 31
1

I am updating a simple solution. First add an id to your segue which presents modal. Than in properties change it's presentation style to "Over Current Context". Than add this code in presenting view controller (The controller which is presenting modal).

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let Device = UIDevice.currentDevice()

    let iosVersion = NSString(string: Device.systemVersion).doubleValue

    let iOS8 = iosVersion >= 8
    let iOS7 = iosVersion >= 7 && iosVersion < 8
    if((segue.identifier == "chatTable")){

    if (iOS8){


          }
        else {

            self.navigationController?.modalPresentationStyle = UIModalPresentationStyle.CurrentContext


        }
    }
}

Make sure you change segue.identifier to your own id ;)

Saqib Omer
  • 5,387
  • 7
  • 50
  • 71