1
votes

My universal app displays both master and detail views in iPad with preferredDisplayMode = .allVisible. I need to expand the master view into full screen and hide the detail view on a button click. I know there is functionality to expand detail into full screen hiding master. But couldn't find how to expand and collapse master view.

I tried in expand function as below.

self.splitViewController.preferredPrimaryColumnWidthFraction = 1.0
self.splitViewController.maximumPrimaryColumnWidth = self.splitViewController.view.bounds.size.width as! CGFloat
    

And collapse function as below.

self.splitViewController.preferredDisplayMode = .allVisible
self.splitViewController.preferredPrimaryColumnWidthFraction = 0.6
self.splitViewController.maximumPrimaryColumnWidth = self.splitViewController.view.bounds.size.width as! CGFloat
    

But they don't work. Any ideas on how to achieve this?

1
Upvoted, but I'm pretty sure this isn't a possible behavior. In iOS 14, it's no longer called "master/detail", but... "primary/secondary"? I honestly hate this nomenclature. Anyways, my issue with this is when rotating from landscape to portrait - the default behavior wa to hide the "primary" VC. It introduced so much complexity that I decided to (a) still use a UISplitViewController due to it displaying a compact VC when in compact size, but (b) only use a secondary VC and "roll my own" primary VC. Maybe that would work for you - show a primary any size you want, when you want.dfd
@dfd hey thanks, I'm using iOS 13 though. Can you please tell more on how you did this? "only use a secondary VC and "roll my own" primary VC"nmy
1/ I decided to make the baseline for this app be iPadOS 14 for two reasons - UIColorPicker and UISplitViewController. The UISplitViewController is needed for it's ability to have a better or different layout when my app is in compact-sized mode, which only happens in certain iPad split screen usages depending on both orientation and device size. But I don't like how the default behavior of the primary/secondary layout, even when showing the primary VC in landscape orientation, will automatically hide it when oriented to portrait - and the code was too complex to go around this.dfd
2/ So I had already had code to have both the primary/secondary (again, I'm not a fan of the names) under a single VC and, using auto layout, show/hide my "tool bar" or "primary" view. Since this tool bar has a lot of things going on in it - UITableViews, UINavigationControllers, etc. - my hierarchy uses child UIViewControllers and their root views. But in the end, the functionality of showing/hiding these tools work with the views - by activating/deactivating NSLayoutContraints and animating the changes. I'd be more than happy to post this code if you'd like.dfd
@dfd thank you. I guess I'll have to work on a similar approach to give it a try. Yeah, would be a great help if you can post the codenmy

1 Answers

0
votes

My setup uses a navigation bar, but the show/hide functionality would probably work without it. What I wanted to achieve is to have the user decide whether to show the "primary" view and have it shown no matter the orientation - something a UISplitViewController doesn't natively do.

I achieved this through activating/deactivating two arrays of constraints, pinning the secondary" view's leading anchor to the "primary's" trailing anchor. From there, all the constraint changes are with the "primary" view.

(I'm using quotation marks because these view's actually have much more logic that a UIView should have, so they are each UIViewControllers with one being a child of the other, but the constraints are view-related.)

Let's start with the static constraints:

primary.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
primary.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
primary.bottomAnchor.constraint(equalTo:  view.safeAreaLayoutGuide.bottomAnchor).isActive = true

secondary.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
secondary.leadingAnchor.constraint(equalTo: toolBar.trailingAnchor).isActive = true
secondaary.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
secondary.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true

Next, define/populate the two arrays that will show/hide the primary:

var isShowingPrimary = false
var showPrimary = [NSLayoutConstraint]()
var hidePrimary = [NSLayoutConstraint]()

showPrimary.append(primary.widthAnchor.constraint(equalToConstant: 300))
hidePrimary.append(primary.widthAnchor.constraint(equalToConstant: 0))

NSLayoutConstraint.activate(hidePrimary)

Notice that isActive is true for the static constraints, and I activated the hidePrimary constraints only.

Now all you need to do is wire up a UIBarButtonItem or UIButton to execute a toggle function that will show/hide the primary view, along with animating it:

func togglePrimary() {
    if isShowingPrimary {
        // hide primary view
        NSLayoutConstraint.deactivate(showPrimary)
        NSLayoutConstraint.activate(hidePrimary)
    } else {
        // show primary view
        NSLayoutConstraint.deactivate(hidePrimary)
        NSLayoutConstraint.activate(showPrimary)
    }
    // toggle flag and animate changes
    isShowingPrimary.toggle()
    UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() }
}