Black screen after presenting modal view controller in current context from UITabBarController

IosObjective CIphoneUikit

Ios Problem Overview


My root view controller is a UITabBarController. I'm trying to present a modal view controller over one of the tab bar controller's view controllers, but still allow the tab bar to be used to go to a different tab - in other words, I would like for the modal to only interrupt to the flow of that particular tab, not the entire app.

To do this, I've set the presenting view controller's presentation style as 'Over Current Context' in storyboard. The problem I'm having is that after presenting the modal view controller and selecting a new tab, the presenting view controller's view is removed from the window, and isn't added back to the window when dismissing the presented view controller. After dismissing the view controller, moving to another tab and then coming back finally puts the presenting view controller back into the window.

I've reproduced my problem using the 'Tabbed' template in Xcode.

After presenting modal - I've added transparency to the presented view controller to easily see what's going on in the presented view controller.

Changing to second tab and then back - the presenting view controller's view has now been removed.

Dismissing the modal leaves the presenting view controller with it's view still removed from the window. Going to tab 2 and returning adds the view back to the window.

I'm hoping this is something simple I've overlooked in storyboard, but the fact that I can present the modal and see the presented view controller behind it before changing tabs makes me think I have things set up correctly.

Ios Solutions


Solution 1 - Ios

I had the same issue and was able to solve it by setting self.definesPresentationContext = YES; on the presenting view controller before presenting the modal VC. You can also set this in a storyboard, the checkbox is called "Defines Context" in Interface Builder.

Solution 2 - Ios

Try to set your presentation style as 'Over Full Screen' instead of 'Over Current Context' in storyboard. enter image description here

Solution 3 - Ios

iOS 10+ & Swift 3+

I've very nice solution of this problem. Use, over full screen modal presentation style for a view controller, is being presented.

let storyboard = UIStoryboard(name: "Main", bundle: nil)  // Replace “Main” with your storyboard name

if let viewController = storyboard?.instantiateViewController(withIdentifier: “viewController Identifier”) as? ViewController {
            viewController.modalPresentationStyle = .overFullScreen
            self.present(viewController, animated: false, completion: { 
            })
        }

Over full screen will present your view controller over your tabbar (controller) by covering it. So, end-user can't switch tabbar (unless you perform operation programatically) tabbar items. User must close this view controller to switch tabbar.

If you are using segue, to present view controller then select 'Over Full Screen' from modal presentation style in Attribute inspection

Solution 4 - Ios

i had this problem : when i present my ModalController it takes transparent background and when i changed the tab to next one in tabBarController and getBack to previous one the transparent background was gone and and there is a bad black background after research i found the point the point is this:

self.definesPresentationContext = true

the self is not modal controller self is that presenting controller for modalController and another point is .overCurrentContext like this

self.definesPresentationContext = true
        modalController.modalPresentationStyle = .overCurrentContext
        self.present(modalController, animated: true, completion: nil)

Solution 5 - Ios

Try presenting the view controller in application window. I had a similar problem which was fixed by below code:

    let myNewVC = mainStoryBoard.instantiateViewController(withIdentifier: "MyNewVCId") as! MyNewVC
    let navController = UINavigationController(rootViewController: myNewVC)
    navController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext    
	
    let appDelegate = UIApplication.shared.delegate as? AppDelegate
    appDelegate?.window?.rootViewController?.present(navController, animated: true, completion: nil)

Hope this helps you too.

Solution 6 - Ios

I reproduced your problem and found a solution. It does not involve changing the segue method or changing some attributes in the storyboard.

Suggestion:

But before going to the solution I would like to add that the purpose of modally presented viewcontrollers is to distrupt the actual flow of the app and present some extra contextual information or some actionable contents for the presenting vc. Simply put it is very logical and actually recommended to cover the tab bar when presenting a view controller modally. There are lots of good examples of it in the app store.

Having said that here is a solution I propose.

Solution:

I believe the problem lies in the way UITabBarController handles its view hierarchy.

What I did was explicitly dismiss the modally presented view controller before the tab was changed. This made the presenting view controller persist in the view hierarchy of the UITabBarViewController before the tab bar switches to new tab.

In the "viewWillDisappear" method of your modally presented ViewController add this.

- (void)viewWillDisappear:(BOOL)animated {
    [self dismissViewControllerAnimated:true completion:^{
    [super viewWillDisappear:animated];
  }];
}

Solution 7 - Ios

Having a similiar issue with my tab controller, however like the comments, I suggest changing the segue to a push or a show segue. This will allow that tab to remain in tact with the new view shown in place of the old view when switching to other tabs. If aesthetics is an issue you can make a custom navigation controller to customize the appearance of the new view.

Solution 8 - Ios

I have same problem in currently live swift project. I have did workaround on that.

Then finally i have used NSNotificationCenter and dismiss that view controller when tab is changed to solve this problem.

I have referenced tabbar controller in AppDelegate and set delegate there.

let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        
let tabbarcontroller = storyboard.instantiateViewControllerWithIdentifier("MyTabBarController") as! UITabBarController
        
tabbarcontroller.delegate = self

And it's delegate as

//MARK: - Tabbar controller delegate

extension AppDelegate : UITabBarControllerDelegate {
    
    func tabBarController(tabBarController: UITabBarController, didSelectViewController viewController: UIViewController) {
        
        NSNotificationCenter.defaultCenter().postNotificationName("TabBarTabChanged", object: nil)
    }
}

Then I have add observer in my presented view controller as

override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PreviewPlaceVC.BackClickAction(_:)), name: "TabBarTabChanged", object: nil)
}

// MARK: - Button Click Actions
    
@IBAction func BackClickAction(sender: AnyObject) {
     self.dismissViewControllerAnimated(true, completion: nil)
}

And it's work fine for me. Not a proper solution I think to dismiss view controller on tab change event, but it is ok to dismiss rather than black screen which also breaks navigation that time.

Solution 9 - Ios

I also needed a Navigation Controller before the calling ViewController!

And I used the described code before:

let newVC = self.storyboard?.instantiateViewController(withIdentifier: "newViewController")
        self.definesPresentationContext = true
        self.providesPresentationContextTransitionStyle = true
        newVC?.modalPresentationStyle = .overCurrentContext //do NOT use .currentContext --> it will produce a black screen by switching over tabbar and close VC
        self.present(newVC!, animated: false)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionalivingstonView Question on Stackoverflow
Solution 1 - IosOle BegemannView Answer on Stackoverflow
Solution 2 - IosmalajisiView Answer on Stackoverflow
Solution 3 - Iosuser7620770View Answer on Stackoverflow
Solution 4 - Iosjamal zareView Answer on Stackoverflow
Solution 5 - IosShobhit CView Answer on Stackoverflow
Solution 6 - Iossaugat gautamView Answer on Stackoverflow
Solution 7 - IosWill Von UllrichView Answer on Stackoverflow
Solution 8 - IosMaxView Answer on Stackoverflow
Solution 9 - IosIng. RonView Answer on Stackoverflow