I am working on an iPad app that seems like a natural fit for using a Master / Detail UISplitViewController for portrait and companion detail controller / popover for navigation.
But... I would sometimes like to use the full screen for the detail controller in portrait as well, turning the master into a popover here as well.
Is there any best practices or sample code explaining how this can be done?
Is a UISplitViewController the appropriate root view?
Any tips that focus on using iOS 5 and segues are especially appreciated. Thanks!
I have discovered that this is possible under iOS 5.
Use the following function in your UISplitViewController delegate:
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return YES;
}
Return YES even in landscape view, and the SplitViewController will function with a popover-style interface just like in portrait. If you want to revert back to the normal split view behavior, use this function to return NO in landscape.
Related
Actually, i want to create an iPad app who will looks like smilar to iPad Settings screen in portrait mode. Where primary view controller has all the list of litems and when i clicked on any item , it will show the detail on particular item.
I tried to create split view controller app but it only shows both controllers in landscape mode.
Thanks in advance.
//This method is in UISplitViewControllerDelegate , first set delegate for your splitviewcontroller object and implement following method in that delegate, i hope it will work for you
- (BOOL)splitViewController: (UISplitViewController*)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return NO;
}
I need a ridiculously simple thing - in one of the detail views of my UISplitViewController I have a button. Clicking it should show/open master view. That's it. Is it even possible?
P.S. it should work for all the layouts (iphone & ipad) and orientations. Even if the detail view part is a navigation and I am deep inside several pages, just want to open master view. You can assume iOS8+.
EDIT: Just to clarify what I meant by "deep inside several pages". Here is my storyboard screenshot:
Suppose I have a button in Detail Page 2 which should show the master. Setting the preferredDisplayMode works only for non-compact sizes, like iPad. On iPhone 6, for example, nothing changes after setting it. The back button points on Detail Page 1 so even swiping doesn't open master, it goes to previous page in detail navigation. I noticed that in this mode there is no split view at all, it is simulated by a navigation controller. So the questions is: is what I need possible at all or am I wrong trying to conceptually treat it as a "left drawer" which can be opened in any case and device?
At iOS8+ you can change visibility of the master view using
an animatable property preferredDisplayMode
#property (nonatomic) UISplitViewControllerDisplayMode preferredDisplayMode
Universal way to change visibility for all iOS versions is overriding delegate method
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return _needsHideMasterView;
}
Here _needsHideMasterView is BOOL ivar which can be changed in your code to hide master view. For example,
- (void)hideMasterView:(BOOL)needsHide
{
_needsHideMasterView = needsHide;
[splitViewController.view setNeedsLayout];
[splitViewController.view layoutIfNeeded];
}
try setting preferredDisplayMode to UISplitViewControllerDisplayModeAllVisible like
self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
I'm currently developing for iOS 8 and developing an app with the new adaptive framework. The weird part is when I use the the splitviewcontroller on iPhone with this storyboard configuration the app does not start with the master view controller but the detail controller. Is this a bug and how could I be able to fix it?
This does only happen if the navigationController that envelops the master exists, if I remove it the app starts with master controller.
The thing to realise is that when a split view controller app starts on iPhone 6 Plus in portrait, it is just showing the split view controller in its collapsed state. By default this has the detailed view pushed above any view controllers in the primary navigation controller.
The way to stop a particular view (such as a blank detail view you may initially show on iPad) from being displayed at launch, or indeed after any rotation to portrait, is to handle this in the splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: delegate method. This will be called at launch on iPhone or iPhone 6 Plus in portrait before presentation.
Doing this, you shouldn't need to have any device specific code.
In its simplest form this would look like:
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController
{
if ([secondaryViewController isKindOfClass:[BlankViewController class]])
{
// If our secondary controller is blank, do the collapse ourself by doing nothing.
return YES;
}
// Otherwise, use the default behaviour.
return NO;
}
Obviously, you then need to do the reverse in splitViewController:separateSecondaryViewControllerFromPrimaryViewController: to create and return a BlankViewController for the new secondary view if you don't want your topmost primary view controller to end up on the detail side after split view expands.
Be aware mixing your own implementation with Apple's in these methods, they do some crazy stuff like embedding UINavigationControllers inside other UINavigationControllers. See my related answer here: https://stackoverflow.com/a/26090823/4089333
UPDATE: Michael Wybrow's answer is better.
I ran into this issue and found this to work:
splitViewController.viewControllers =
UIScreen.mainScreen.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact ?
#[ leftNavigationController ] :
#[ leftNavigationController, rightNavigationController ]
;
And in the splitview delegate:
- (UIViewController *)primaryViewControllerForCollapsingSplitViewController:(UISplitViewController *)splitViewController
{
return leftNavigationController;
}
- (UIViewController *)primaryViewControllerForExpandingSplitViewController:(UISplitViewController *)splitViewController
{
return leftNavigationController;
}
- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController
{
return rightNavigationController;
}
It's horrible, I know. But it does the right thing, especially on the iPhone 6 Plus, which is very tricky to get right.
UPDATE: Michael Wybrow's answer is better.
It is probably an error due to the SplitViewController being just exclusive to the iPad. Also when you have it in the portrait orientation, it displays the detail view by default and the master view will show as a bar. You will have to change it using some method like splitViewController:shouldHideViewController:inOrientation
Here is an Apple document referring your problem
https://developer.apple.com/library/ios/documentation/uikit/reference/UISplitViewController_class/Reference/Reference.html
I hope this helps!
I have nice helper functions that allow me to show/hide the master popover view controller. However, I can not for the life of me figure out how to hide it on initialization, so that it is hidden when the app first starts.
I've tried a couple of things (such as trying to dismiss is from the viewLoaded or viewDidAppear) but these throw strange errors (e.g. too made slider counts...etc).
Now I'm starting to believe there must be a simpler, and the right way, to do this.
Are you trying to hide the splitviewController Master Popover? Which orientation would make this question more specific. I will assume you are in fact trying to hide the SplitView MasterPopover in landscape (since it should already be hidden in portrait).
Do this:
Your detailViewController should have UISplitViewControllerDelegate. And simply just drop this code in:
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation{
return YES;
}
This will make popoverView hidden when the app starts up. Let me know, if it works for you.
Apple provide the split view only for landscape but not for the portrait mode. Is there any way to achieve the splitview in portrait mode also?
[splitViewController setHidesMasterViewInPortrait:NO];
This will work. But this API is not documented(private).
Thanks,
Manjunath
For iOS5+,
Go to your detailViewController. Your detailViewController should have UISplitViewControllerDelegate. And simply just drop this code in:
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation{
return NO;
}
This will do the trick. And it is public API.
My little contribution here.
Byte's answer is correct up until iOS 7. Starting in iOS 8 you should use preferredDisplayMode
For example, to show both view controllers in portrait mode do the following:
self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
Hope this helps!
update in iOS 8 xcode 6+
if let splitVCExists = self.splitViewController{
splitVCExists.preferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible
}
doc:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UISplitViewController_class/index.html#//apple_ref/occ/instp/UISplitViewController/preferredDisplayMode
One thing I did notice is that it will try to layout the splitviewcontroller based on the preferredDisplayMode as long as there is enough space. otherwise it will choose the display mode to fit the content right. I have used it and it lays the VCs out how I want in both portrait and landscape.
Take a look at this MGSplitViewController.
It is a customized split view controller with various useful enhancements. Certainly that you can show master view in portrait.
Have a look at APSplitViewController.
Sometime back I tried to achieve a similar thing. After trying Matt's code, and unsucessfully trying to create a category I realized that the only way to do this(in a way that Apple doesn't reject your app) is to use two custom views. Refer this question.