kmiklas
kmiklas

Reputation: 13463

How to present a modal atop the current view in Swift

(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

Upvotes: 42

Views: 141859

Answers (7)

Hardik Thakkar
Hardik Thakkar

Reputation: 15991

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)

Upvotes: 24

AceRam
AceRam

Reputation: 279

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)
}

Upvotes: 14

user7097242
user7097242

Reputation: 1074

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)
}

Upvotes: 2

Riskov
Riskov

Reputation: 832

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.

Upvotes: 46

Tekla Keresztesi
Tekla Keresztesi

Reputation: 59

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.

Upvotes: 2

Ivens Denner
Ivens Denner

Reputation: 533

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

Upvotes: 13

Saqib Omer
Saqib Omer

Reputation: 5477

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 ;)

Upvotes: 1

Related Questions