UITab view controller not being displayed when tapped from within a UITabGroup

The following:

tabBarController.tabs = [
			UITab(title: "First",
				  image: UIImage(...),
				  identifier: "First Tab") { _ in
					  myViewController()
				  }

Works as expected. Tap on a a tab or sidebar item, and myViewController appears.

However, the following:

let collectionsGroup = UITabGroup(
			title: "Lists",
			image: nil,
			identifier: "Tabs.CollectionsGroup",
			children: [
				UITab(title: "First", image: nil, identifier: "First Tab") { _ in
					myViewController()
				}
			]) { _ in
				fallbackViewController()
			}

Does not work as expected. Tapping on any tab in the sidebar always displays fallbackViewController, instead of myViewController or any other specified view controllers in the given tab.

Am I doing something wrong, or is this a bug with the current betas?

Answered by Frameworks Engineer in 798795022

By default, UITabBarController will only change the view controller for root tabs. Apps can manage how the view controller hierarchy changes within that root tab through system callbacks from UITabBarControllerDelegate.

That being said, starting in iOS 18 beta 5, there is new UITabBarController API that will manage this for you automatically.

Setting managingNavigationController on UITabGroup will opt-in the specified group to allow UITabBarController to automatically manage its hierarchy for you. Once set, UITabGroup will basically create a navigation stack based on the selected hierarchy in that group.

let group = UITabGroup(...)
group.managingNavigationController = UINavigationController()

Let's consider the following UITab hierarchy:

Group A
    | Tab 1
    | Tab 2
    | Group B
        | Tab B1
        | Tab B2
    | Tab 3

When selection occurs, UITabBarController will rebuild the navigation stack to represent the hierarchy as needed. For example, selecting Tab B2 will create a navigation stack of:

GroupAVC → GroupBVC → TabB2VC

Selecting Tab 3 will change the hierarchy to:

GroupAVC → Tab3VC

To customize the displayed view controller, there is also new API in iOS 18 beta 5 in UITabBarControllerDelegate:

func tabBarController(
    _ tabBarController: UITabBarController,
    displayedViewControllersFor tab: UITab,
    proposedViewControllers: [UIViewController]
) -> [UIViewController]

This API allows you to insert or remove view controllers when UITabBarController is rebuilding the tab group's navigation stack. Additional view controllers pushed from the leaf view controller (that are not represented by a UITab) will also be preserved as part of proposedViewControllers when switching between regular and compact size classes. This makes it easy for apps to alter its navigation hierarchies without manually managing everything themselves.

I hope that helps. :)

Accepted Answer

By default, UITabBarController will only change the view controller for root tabs. Apps can manage how the view controller hierarchy changes within that root tab through system callbacks from UITabBarControllerDelegate.

That being said, starting in iOS 18 beta 5, there is new UITabBarController API that will manage this for you automatically.

Setting managingNavigationController on UITabGroup will opt-in the specified group to allow UITabBarController to automatically manage its hierarchy for you. Once set, UITabGroup will basically create a navigation stack based on the selected hierarchy in that group.

let group = UITabGroup(...)
group.managingNavigationController = UINavigationController()

Let's consider the following UITab hierarchy:

Group A
    | Tab 1
    | Tab 2
    | Group B
        | Tab B1
        | Tab B2
    | Tab 3

When selection occurs, UITabBarController will rebuild the navigation stack to represent the hierarchy as needed. For example, selecting Tab B2 will create a navigation stack of:

GroupAVC → GroupBVC → TabB2VC

Selecting Tab 3 will change the hierarchy to:

GroupAVC → Tab3VC

To customize the displayed view controller, there is also new API in iOS 18 beta 5 in UITabBarControllerDelegate:

func tabBarController(
    _ tabBarController: UITabBarController,
    displayedViewControllersFor tab: UITab,
    proposedViewControllers: [UIViewController]
) -> [UIViewController]

This API allows you to insert or remove view controllers when UITabBarController is rebuilding the tab group's navigation stack. Additional view controllers pushed from the leaf view controller (that are not represented by a UITab) will also be preserved as part of proposedViewControllers when switching between regular and compact size classes. This makes it easy for apps to alter its navigation hierarchies without manually managing everything themselves.

I hope that helps. :)

UITab view controller not being displayed when tapped from within a UITabGroup
 
 
Q