I am using a Universal Storyboard in Xcode 6, targeting iOS 7 and above. I've implemented a UISplitViewController
which is now natively supported on iPhone running iOS 8, and Xcode will automatically backport it for iOS 7. It's working really well, except when you launch the app on iPhone in portrait running iOS 8, the split view's detail view controller is displayed when I expected to first see the master view controller. I believed this was a bug with iOS 8 because when you run the app on iOS 7, it correctly shows the master view controller. But iOS 8 is now GM and this is still occurring. How can I set it up so that when the split view controller is going to be collapsed (only one view controller displayed on screen), when the split view controller is displayed it shows the master view controller not the detail?
I've created this split view controller in Interface Builder. The split view controller is the first view controller within a tab bar controller. Both the master and the detail VCs are navigation controllers with table view controllers embedded inside.
For all the people who couldn't find cs193p's friday section:
In Swift 3.1.1 creating a subclass of UISplitViewController and implementing one of its delegate methods worked for me like a charm:
My storyboard
In my opinion you should solve this problem more generic. You can subclass the UISplitViewController and implement a protocol in the embedded view controllers.
Example implementation in UITableViewController:
Hope it helps. So you can reuse this class and just need to implement a protocol.
Oh man, this was causing me a headache for a few days and could not figure out how to do this. The worst part was that creating a new Xcode iOS project with the master-detail template worked just fine. Fortunately, in the end, that little fact was how I found the solution.
There are some posts I've found that suggest that the solution is to implement the new
primaryViewControllerForCollapsingSplitViewController:
method onUISplitViewControllerDelegate
. I tried that to no avail. What Apple does in the master-detail template that seems to work is implement the new (take a deep breath to say all of this one)splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
delegate method (again onUISplitViewControllerDelegate
). According to the docs, this method:Make sure to read up on the discussion part of that method for more specific details.
The way that Apple handles this is:
This implementation basically does the following:
secondaryViewController
is what we're expecting (aUINavigationController
), and it's showing what we're expecting (aDetailViewController
-- your view controller), but has no model (detailItem
), then "Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
"NO
to let the split view controller try and incorporate the secondary view controller’s content into the collapsed interface"The results are the following for the iPhone in portrait (either starting in portrait or rotating to portrait -- or more accurately compact size class):
Clear as mud.
From the documentation, you need to use a delegate to tell the
UISplitViewController
not to incorporate the detail view into the "collapsed interface" (i.e. the "Portrait mode" in your case). In Swift 4, the delegate method to implement for that has been renamed:Swift version of Mark S' correct answer
As provided by Apple's Master-Detail template.
Clarification
(What Mark S said was slightly confusing)
This delegate method is called
splitViewController: collapseSecondaryViewController: ontoPrimaryViewController:
, because that's what it does. When changing to a more compact width size (for example when rotating the phone from landscape to portrait), it needs to collapse the split view controller into only one of them.This function returns a boolean to decide if it should collapse the Detail and show the Master or not.
So in our case, we'll decided based on if there was a detail selected or not. How do we know if our detail is selected? If we follow Apple's Master-Detail template, the detail view controller should have an optional variable having the detail info, so if it's nil (.None), there's nothing selected yet and we should show the Master so the user can select something.
That's it.
Just remove DetailViewController from SplitView controllers when you need it to start from Master.