6
votes

I've done a lot of research and read a lot about the use of Tab Bar Controllers with Split View Controllers but cannot seem to find any hint of how to solve my problem...

The following post in the Apple Developer Forum for Cocoa Touch under the heading "Place SplitViewController inside TabBarController" has so far given me the greatest lead.

As of iOS 8, embedding a Split View Controller in a tab bar controller (or your own container view controller) is supported and expected to 'just work'. Pushing a split view controller onto a navigation stack remains unsupported.

This appears to go against Apple Documentation including this article titled "Combined View Controller Interfaces" dated November 2014.

You can use the view controllers that the UIKit framework provides by themselves or in conjunction with other view controllers to create even more sophisticated interfaces. When combining view controllers, however, the order of containment is important; only certain arrangements are valid. The order of containment, from child to parent, is as follows:

  • Content view controllers, and container view controllers that have flexible bounds (such as the page view controller)
  • Navigation view controller
  • Tab bar controller
  • Split view controller

I have a UITabBarController with seven tabs. Of these, five tabs lead to UISplitViewControllers and two tabs lead to UINavigationControllers.

Here is a screenshot of some of the storyboard the shows the tab bar controller leading to three of the five split view controllers... Screenshot of <code>UIStoryboard</code>

No problem when I run for target with self.traitCollection.horizontalSizeClass = UIUserInterfaceSizeClassRegular - where the horizontal (width) dimension of the device screen is Regular (not Compact) -> running on an iPad. All seven tabs appear across the bottom tab bar and all view controllers, including split view controllers, work perfectly.

My problem?

Xcode spits an error and freezes app operation when I run for target with self.traitCollection.horizontalSizeClass = UIUserInterfaceSizeClassCompact - where the horizontal (width) dimension of the device screen is Compact -> running on iPhone or iPhone Plus. Same outcome, as expected, for both IB and on iOS device.

Error Message: Split View Controllers cannot be pushed to a Navigation Controller <UIMoreNavigationController: 0x7ffda38b0200>

I know why I've received the error. Where the horizontal size class is "Compact", the seven tabs drops to five on screen, including one (specially prepared by iOS) "More" tab. The remaining three tabs are relegated to the "More" tab that is its own navigation controller and table view controller. My storyboard is attempting to push the split view controller onto this navigation stack.

Any thoughts on a legitimate solution?

1
How did building a custom tab bar controller go? I am surprised this situation isn't more common.C. Skjerdal
@C.Skjerdal that's an interesting question and the answer is perhaps too convoluted to provide in comments, so I might update my question... essentially a custom tab bar is possible but complicated. Some apps use the hamburger icon to open/close a side bar menu to overcome tab bar limitations on Compact size class. I prefer the easier-in-the-long-run alternative task of UI interrogation, to challenge the bare minimum required in the tab bar for the app to be easy to use, provide access to needed functions/features through other controls and view controllers.andrewbuilder

1 Answers

0
votes

I would recommend using a custom tab bar controller with a "More" section that does not push view controllers into a navigation controller. Preferably, one that is a subclass of UITabBarController, so you can use it with Interface Builder.

My approach would be to replace the current "More" table view controller with a view controller of your own that shows a list of overflowing tabs, but does not push their corresponding view controllers into the navigation bar when displayed.

One possible strategy is to become the delegate of the UITabBarController's more navigation controller (found in the tab bar controller's moreNavigationController property). Then use a delegate method, such as navigationController:willShowViewController:animated:, to replace the content of the navigation controller's viewControllers array if the view controller to be displayed is anything but your custom "More" view controller.

I haven't tried this, but it seems like a good place to start and does not require too much knowledge of the tabview controller's internals.