8

In iOS 14, the new split view controller handles the bar button items for you. That's cool! So in portrait we see this:

enter image description here

We're in portrait, so that button at the top left summons the "overlay" version of the Primary column.

And in landscape we see this:

enter image description here

We're in landscape, so that button at the top left hides or shows the "side by side" version of the Primary column.

Now I want to know how to control the presence of these buttons individually. I see that I can set presentsWithGesture to false to hide both buttons, but that's not what I want. My question is: how can I hide the second button (landscape) but not the first button (portrait)?

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • @dfd I can't work out what you're hinting at, sorry. – matt Oct 26 '20 at 02:18
  • @dfd I'm afraid I don't know what a "navigation bar override" is. – matt Oct 26 '20 at 03:52
  • @dfd I wasn't able to find a way to do that. My attempts to say things to `self.navigationItem` failed to suppress the button. – matt Oct 26 '20 at 18:46
  • Deleted our conversation, as it really didn't help and was noise. Apple decided that the default behavior for a UISplitViewController "is what it is" - and the lack of other comments/answers implies that. A few years ago I was faced with an issue where portrait/landscape orientation meant more than Apple defaults - first in IB (Xcode 8?), then with size classes (at the time iPads were *always* regular). I now see that split screen changes that for iPads. Maybe in a year or two this default behavior will make it more apparent. –  Oct 27 '20 at 16:00
  • @dfd thanks, it's okay, I figured it out – matt Oct 27 '20 at 17:11

2 Answers2

8

Set a delegate on the split view controller and implement this delegate method:

func splitViewController(_ svc: UISplitViewController, willChangeTo displayMode: UISplitViewController.DisplayMode) {
    svc.presentsWithGesture = displayMode != .oneBesideSecondary
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
6

In SwiftUI, this solution works – tested on iOS 16!

extension UISplitViewController {
    open override func viewDidLoad() {
        preferredDisplayMode = UISplitViewController.DisplayMode.oneBesideSecondary
        
        // remove sidebar button, make sidebar always appear !
       presentsWithGesture = displayMode != .oneBesideSecondary
        
    }
}
LinusGeffarth
  • 27,197
  • 29
  • 120
  • 174
Basel
  • 550
  • 8
  • 21
  • Thanks for your answer. I hadn't thought of this pattern! It opened my mind to the possibility of extending UIKit this way to customize class settings. In cases like this, it's way better than relying on something like Introspect to do it after the render has already happened. – John Gorenfeld Oct 24 '22 at 09:02
  • Can confirm this also works for me, thanks! It's worth noting this can be fragile in the future if the underlying view of `NavigationSplitView` changes from `UISplitViewController` to something else such as a newer Swift-only version. – Paolo Apr 11 '23 at 13:54