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
Swift - How to Get Last Taken 3 Photos from Photo Library
How to Capture Picture with Avcapturesession in Swift
iOS Autolayout Vertically Equal Space to Fill Parent View
Objc_Sync_Enter/Objc_Sync_Exit Not Working with Dispatch_Queue_Priority_Low
How to Disable Caching from Nsurlsessiontask
Right Aligned Uitextfield Spacebar Does Not Advance Cursor in iOS 7
Using Custom Fonts in Interface Builder
Post Request with Data in Body with Alamofire 4
Firebase for iOS, Googleservice-Info.Plist Property "Is_Analytics_Enabled" Set to "No"
Stretch Background Image for Uibutton
How to Get Current Longitude and Latitude Using Cllocationmanager-Swift
Disabled Uibutton Not Faded or Grey
Avplayer Resuming After Incoming Call
iOS Playground Doesn't Show UI Preview