Black Screen After Presenting Modal View Controller in Current Context from Uitabbarcontroller

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

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.

Black screen after presenting model view controller in current context from tab controller

Set definesPresentationContext property to true of UIViewController in first viewController where you're displaying pop-view

override func viewDidLoad() {
super.viewDidLoad()
definesPresentationContext = true
}

iOS Black screen when close modally presented view controller

You can do it with UITabBarControllerDelegate.

Option 1: Creating subclass of UITabBarController

class MyTabBar: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if let currentlySelectedViewController = self.viewControllers?[self.selectedIndex] as? YourThirdTabViewController,
let presentedViewController = currentlySelectedViewController.presentedViewController {
presentedViewController.dismiss(animated: false, completion: nil)
}
return true
}
}

Here I am assuming that I have my own sub class of UITabBarController which is set as UITabBarControllerDelegate using self.delegate = self in view didLoad.

Option 2: Make TabBarController's ViewController UITabBarControllerDelegate in their ViewDidLoad

If you dont wanna have your own subclass of UITabBarController all you have to do is simply set your self as UITabBarControllerDelegate in each ViewController's ViewDidLoad

You can have a common protocol or extension to UIViewController and confirm UITabBarControllerDelegate to avoid code duplication if you decide to go down the path of not subclassing UITabBarController

protocol TabBarControllerProtocol: UITabBarControllerDelegate where Self: UIViewController {}

extension TabBarControllerProtocol {
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if let currentlySelectedViewController = self.tabBarController?.viewControllers?[self.tabBarController?.selectedIndex ?? 0] as? SomeViewController,
let presentedViewController = currentlySelectedViewController.presentedViewController {
presentedViewController.dismiss(animated: false, completion: nil)
}
return true
}
}

In whichever ViewController, you want this logic to kick in you can say

class SomeViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.delegate = self
}
}

extension SomeViewController: TabBarControllerProtocol {}

Thats it.

shouldSelect viewController gets called every time user taps on tab to switch.

The if condition checks if ViewController at selectedIndex (already selected not the new one) is viewController of specific interest or not and also checks if this view controller has presented anything or not, if it has presented it will call dismiss on it

This way when user switches tab from 3rd tab to any other tab, if third tab VC has presented another view controller modally it will dismiss it before it switches tab.

Dismissing modal view controller results in a black screen

I found the solution - this answer really helped. The trick was in dismissing the view controller. It should be done like this:

[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];

and not like this:

[self dismissViewControllerAnimated:YES completion:nil];

Although the author of the linked answer suggests that a better approach would be to use delegation (presentED VC would define a protocol and presentING VC would subscribe to it and then dismiss the presentED VC once it asks for it), it wasn't feasible in my case.

UITabBarController's viewControllers present modal controller issue

If this is the same bug that I demonstrate here, the workaround I give is to prevent the user from switching to another tab while this tab is showing the presented view controller:

override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.delegate = self
}
extension FirstViewController : UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
return self.presentedViewController == nil
}
}

Presenting a modal from a UITabBarController

tldr - Check out the code below.

I started with axxixc's approach but ran into some issues. I was attempting to show the view modally by implementing tabBarController:shouldSelectViewController: of UITabBarControllerDelegate. However, iOS was complaining about the view already being in the view hierarchy, which is obvious once you think about it because the whole point of using the UITabBarController in IB is so that iOS handles instantiating these views for us. So next I removed the view from it's parent and that stopped the errors but the approach still felt wrong and brittle. It also didn't give me any control over whether I wanted to re-instantiate the view each time the model popped up, which in my case I did.

So what I ended up doing is, in IB, connecting that specific tab to an empty view controller that would effectively act as a placeholder. I override the same tabBarController:shouldSelectViewController: method and check for the title of the view controller. If it matches the dummy title that I set in IB, I stop the tab bar controller from showing the dummy controller by returning false after showing my own view modally.

Here's the code:

func tabBarController(tabBarController: UITabBarController!, shouldSelectViewController viewController: UIViewController!) -> Bool {
if viewController.title? == DUMMY_POST_VIEW_CONTROLLER_TITLE {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let actualController = storyboard.instantiateViewControllerWithIdentifier("ActualViewController") as ActualViewController
presentViewController(actualController, animated: true, completion: nil)
return false
}

return true
}


Related Topics



Leave a reply



Submit