IBG
IBG

Reputation: 465

displayModeButtonItem is disappearing when I collapse/expand screen

So my use-case is that I have a TabBarController in the detailview, and around four tabs each with its own NavigationController. All are via storyboard. Then on my App Delegate I have this:

let splitViewController = self.window!.rootViewController as! UISplitViewController
splitViewController.preferredDisplayMode = .allVisible
let tabBarController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UITabBarController
for item in tabBarController.viewControllers!{
        let navigationController = item as! UINavigationController
        navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
}

And so I have a Button on each NavigationController. The issue is at first when I use the button on the first tab, it works fine, but as soon as I move tabs, when I return to the previous tabs and use the button, it disappears. Then, when I switch to another tab, it goes back. Surprisingly, this doesn't happen on the last tab. I've tried to search for a solution but I can't find any. And so I'm in a slump right now.

I added a gif to show the behavior.

enter image description here

EDIT: I don't know if this matters, but this project is landscape-only.

Upvotes: 2

Views: 1023

Answers (2)

IBG
IBG

Reputation: 465

I'll add an answer as an additional information per the official support from Apple, in case anyone wonders:

"UISplitViewController’s displayModeButtonItem can only reside in one place in the view hierarchy at a time, not in multiple places or multiple view controllers. Currently you are pointing it to all the view controllers in the tabbar. Doing so yields unpredictable results as we have seen."

The accepted answer, though quite a hacky workaround, works. Apple's support recommendation though, is work on it in the TabBarController level.

Upvotes: 3

Egor Komarov
Egor Komarov

Reputation: 523

I believe this is a UIKit bug. Behavior actually depends on the order of view controllers, on which you set navigationItem.leftBarButtonItem. The bug will start reproducing after view of the last one of them will be loaded.

There is a hacky workaround though. Add this to the object, which implements UISplitViewControllerDelegate of your UISplitViewController

func splitViewController(_ svc: UISplitViewController, willChangeTo displayMode: UISplitViewControllerDisplayMode) {
    DispatchQueue.main.async {
        let tabBarController = svc.viewControllers.last as! UITabBarController
        let navigationController = tabBarController.selectedViewController as! UINavigationController
        navigationController.viewControllers.first?.navigationItem.leftBarButtonItem = nil
        navigationController.viewControllers.first?.navigationItem.leftBarButtonItem = svc.displayModeButtonItem
    }
}

It will work without DispatchQueue.main.async, but leftBarButtonItem's position would be wrong for some reason, and I don't know a way to update it's layout.

Hope it helps.

Upvotes: 2

Related Questions