I ended up getting around this by not using a UITabBarController
, instead creating a CustomTabBarController which inherits from UIViewController
. The custom controller has a UITabBar
at the bottom of its view, and multiple other UIViewController
s embedded in Container Views. The custom controller sets the isHidden
property to true
for of all of the embedded view controller except the one which corresponds to the selected tab.
The following is a simple example with two tabs, identified by their tag:
class CustomTabBarController: UIViewController, UITabBarDelegate {
@IBOutlet weak var tab1View: UIView!
@IBOutlet weak var tab2View: UIView!
@IBOutlet weak var tabBar: UITabBar!
override func viewDidLoad() {
tabBar.delegate = self
}
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
tab1View.isHidden = item.tag != 1
tab2View.isHidden = item.tag != 2
}
}
This custom controller should be set to the root of a UINavigationController
, which itself should be set as the master controller of the Split View Controller:
This setup works for both iPad and iPhone:
There are a few drawbacks to this method:
The custom tab controller is less easy to work with - adding a new tab requires that you add another embedded view and connect it to an outlet in the controller.
Setting the navigation item's title and left and right bar button items must be done within the custom tab bar controller, upon tab selection.
This method uses (I think) more memory than a regular UITabBarController
, since all of the child view controllers are loaded as soon as the app loads, rather than when they are first shown.
This setup will lead to the tab bar being hidden when detail is shown in (portrait) iPhone mode. This was what I wanted, and is the behaviour in the Facebook Messenger app too, but if you want the tab bar to be permanently visible, this method won't do it.