Open UISplitViewController to Master View rather than Detail
Swift
UISplitViewController display master view above detail in portrait orientation is not about showing the Master view, it is about presenting the Detail view in full width, underneath the Master view.
UISplitViewController in portrait on iPhone shows detail VC instead of master is about the principle of the collapse mechanism.
This present answer addresses:
- Master → Detail (Compact width)
- iPhone 4s, 5, 5s, SE, 6, 6s, 7 (any orientation)
- iPod Touch
- any iPhone Plus (portrait)
- side-by-side (all other sizes)
- iPad
- any iPhone Plus (landscape)
You must set preferredDisplayMode
. You would want is .primaryVisible
if it existed! Using .allVisible
, iOS picks Detail
if only 1 view fits (Compact width); in that size, the code below will pick Master
.
The trick is to change both the preferredDisplayMode
to .allVisible
and to return true
in collapseSecondary:onto
.
class PrimarySplitViewController: UISplitViewController,
UISplitViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.preferredDisplayMode = .allVisible
}
func splitViewController(
_ splitViewController: UISplitViewController,
collapseSecondary secondaryViewController: UIViewController,
onto primaryViewController: UIViewController) -> Bool {
// Return true to prevent UIKit from applying its default behavior
return true
}
}
How to let UISplitViewController on Storyboard show master view first?
In order to enable the master view to collapse on iPhone by default, override some delegate methods:
class SplitViewController : UISplitViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
}
extension SplitViewController : UISplitViewControllerDelegate {
// The default for this is .secondary!!
@available(iOS 14.0, *)
public func splitViewController(_ svc: UISplitViewController,
topColumnForCollapsingToProposedTopColumn
proposedTopColumn: UISplitViewController.Column) -> UISplitViewController.Column {
return .primary
}
// default is false!
public func splitViewController(_ splitViewController: UISplitViewController,
collapseSecondary secondaryViewController:UIViewController,
onto primaryViewController:UIViewController) -> Bool {
return true
}
}
Previously you'd use preferredDisplayMode = .primaryOverlay
, but this is now deprecated. The code works for iOS 14 and is backwards compatible for earlier iOS versions also.
iOS SplitViewController: Show master view when loading in compact width
You should use method
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool
which provided by UISplitViewControllerDelegate
UISplitViewController display master view above detail in portrait orientation
Edit: It's not a duplicate. Answer discovered in the comments. The solution is to use preferredDisplayMode
on UISplitViewController and setting it to UISplitViewControllerDisplayModePrimaryOverlay
Left the original answer for context to the comments and posterity.
Original Answer
This is a duplicate of this: UISplitViewController in portrait on iPhone shows detail VC instead of master
For reference, the solution in that case was to have the view controller that implements UISplitViewControllerDelegate
use the following code:
- (BOOL)splitViewController:(UISplitViewController *)splitViewController
collapseSecondaryViewController:(UIViewController *)secondaryViewController
ontoPrimaryViewController:(UIViewController *)primaryViewController {
if ([secondaryViewController isKindOfClass:[UINavigationController class]]
&& [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[DetailViewController class]]
&& ([(DetailViewController *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil)) {
// Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return YES;
} else {
return NO;
}
}
Swift UISplitViewController - unable to present master view before detail view (iOS 14, Xcode 12.4)
Returning .primary should solve your issue.
@available(iOS 14.0, *)
public func splitViewController(_ svc: UISplitViewController, topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column) -> UISplitViewController.Column {
return .primary
}
[From Documentation]
Asks the delegate to provide the column to display after the split view interface collapses.
When the split view controller transitions from a horizontally regular to a horizontally compact size class, it calls this method and asks you for the column to display when that transition is complete. Use this method to customize the view controller you’re collapsing to.
UISplitViewController detail view controller loads in master view window
If the segues were already there then try removing the segues from the master view to the other detail views and recreating them using a detail segue.
In UISplitViewController, how to make master open detail view controller for iPhone?
At very first, why you need both functionalities : Master-Detail
and Tab
. Because if you are implementing master detail with tab then you must have equal number of tab with the equal number of rows in Master
, then only you can navigate to the tab when you select row. In iPhone there would be max 5 tabs only and if you have 7 rows in Master
then what happened if user will click on row 6 and 7?
Because as per design concept : You should choose only one as per requirements.
Master-Detail
-> Provides facilities like side menu, so user can access many more option from these.TabBar
-> Provide facilities of more option with having menu at bottom.
Anyway, you might have some unique requirement.
As you said on iPad it is working fine. So for iPhone you can go with below way :
- UI in storyboard should be like :
- Create or add
UITabBarController
in your project. (I have created tabbarcontroller namedCustomTabController
). Then in
didSelectRowAt
, push tabbarcontroller :override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.phone {
let tabController = self.storyboard?.instantiateViewController(withIdentifier: "CustomTabController") as! CustomTabController
self.navigationController?.pushViewController(tabController, animated: true)
tab.selectedIndex = indexPath.row
}
else {
// iPad code here
}
}
But make sure, that you have enough number of tabs same as number of rows.
UISplitViewController in portrait on iPhone shows detail VC instead of master
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 on UISplitViewControllerDelegate
. 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 on UISplitViewControllerDelegate
). According to the docs, this method:
Asks the delegate to adjust the primary view controller and to incorporate the secondary view controller into the collapsed interface.
Make sure to read up on the discussion part of that method for more specific details.
The way that Apple handles this is:
- (BOOL)splitViewController:(UISplitViewController *)splitViewController
collapseSecondaryViewController:(UIViewController *)secondaryViewController
ontoPrimaryViewController:(UIViewController *)primaryViewController {
if ([secondaryViewController isKindOfClass:[UINavigationController class]]
&& [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[DetailViewController class]]
&& ([(DetailViewController *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil)) {
// Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return YES;
} else {
return NO;
}
}
This implementation basically does the following:
- If
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.
" - Otherwise, return "
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):
- If your view is correct
- and has a model, show the detail view controller
- but has no model, show the master view controller
- If your view is not correct
- show the master view controller
Clear as mud.
Related Topics
What Is a Provisioning Profile Used for When Developing iPhone Applications
Keeping the Contentoffset in a Uicollectionview While Rotating Interface Orientation
Face Recognition on the Iphone
Pods-Resources.Sh Permission Denied in iOS Project
How to Develop iPhone Mdm Server
Modify Uiimage Renderingmode from a Storyboard/Xib File
How to Dismiss the iOS Keyboard
Steps to Create and Edit a Plist File in Xcode
How to Open the Imagepicker in Swiftui
How to Get Back "Allow Push Notifications" Dialog After It Was Dismissed Once
Allow Unverified Ssl Certificate in Uiwebview
Warning Frame for "Navigation Bar" Will Be Different at Run Time Appears in Xcode 8 Swift 3
How to Hide "-" (Delete) Button While Editing Uitableview
How to Call a View Controller Programmatically
Code Signing Is Required for Product Type Unit Test Bundle in Sdk iOS 8.0
iOS 7 and Later: Set Status Bar Style Per View Controller