Reputation: 95
I've tried to expand the default Apple MasterDetail Template by adding a UITabbarController in front of the UINavigationController of the MasterView, so there is a structure like this:
UISplitViewController (Master) > UITabbarController > UINavigationController > UITableViewController
But if I run the App, after changing application(didFinishLaunchingWithOptions) to use the correct ViewController, and try to perform the ShowDetails Segue the DetailsView ist presented Modally on the iPhone. On the other side the iPad Version is working as expected. What am I forgot to do? Or how can I fix it?
Upvotes: 9
Views: 2437
Reputation: 113
Subclass TabBarController like this:
- (void)showViewController:(UIViewController *)vc sender:(id)sender
{
if ([self.selectedViewController isKindOfClass:UINavigationController.class])
[self.selectedViewController showViewController:vc sender:sender];
else
[super showViewController:vc sender:sender];
}
- (UIViewController*)separateSecondaryViewControllerForSplitViewController:(UISplitViewController *)splitViewController
{
return [self.selectedViewController separateSecondaryViewControllerForSplitViewController:splitViewController];
}
- (void)collapseSecondaryViewController:(UIViewController *)secondaryViewController forSplitViewController:(UISplitViewController *)splitViewController
{
[self.selectedViewController.navigationController collapseSecondaryViewController:secondaryViewController forSplitViewController:splitViewController];
}
See this question for complete explanation.
Upvotes: 1
Reputation: 4319
Just to update the answers above. Since you can't push navigation controllers anymore, you have to push its top view controller instead.
func splitViewController(splitViewController: UISplitViewController, showDetailViewController vc: UIViewController, sender: AnyObject?) -> Bool {
if splitViewController.collapsed {
let tabBarController = splitViewController.viewControllers.first as! UITabBarController
let selectedNavigationViewController = tabBarController.selectedViewController as! UINavigationController
// Push view controller
var viewControllerToPush = vc
if let navController = vc as? UINavigationController {
viewControllerToPush = navController.topViewController
}
selectedNavigationViewController.pushViewController(viewControllerToPush, animated: true)
return true
}
return false
}
Upvotes: 7
Reputation: 405
There is another way to do it without code.
After you embedded the the UINavigationController in the TabBarController embed the TabBarController in another UINavigationController. So you will have: SplitViewController -> Master -> NavCon -> TabBar -> NavCon -> TableViewController.
It's much easier doing like this, but there a bug that I haven't found out how to fix. The navigation bar presented will be that of the TabBarController, not the TableViewController. Any ideas how to fix that?
Upvotes: 1
Reputation: 134
Here is an alternative that is based on testing the size classes of the splitViewController :
Here is the the code of the custom UISplitViewController :
import UIKit
class CustomSplitViewController: UISplitViewController {
override func showDetailViewController(vc: UIViewController!, sender: AnyObject!) {
if (self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.Compact) {
if let tabBarController = self.viewControllers[0] as? UITabBarController {
if let navigationController = tabBarController.selectedViewController as? UINavigationController {
navigationController.showViewController(vc, sender: sender)
return
}
}
}
super.showDetailViewController(vc, sender: sender)
}
}
Do not forget to the set the custom class in the storyboard.
Tested in the simulator of iPhone 6, iPhone 6+ and iPad Air and worked as expected.
Upvotes: 0
Reputation: 1225
Here's my solution. Place in MasterViewController.m and remember to give your detail view a Storyboard ID in IB. In my case 'detail'.
-(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
if ([identifier isEqualToString:@"showDetail"] && self.splitViewController.collapsed) {
DetailViewController *myController = (DetailViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"detail"];
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
[myController setDetailItem:object];
[self.navigationController showViewController:myController sender:self];
return NO;
}
return YES;
}
Upvotes: 1
Reputation: 468
I figured out how to put the detail on to the master's UINavigationController instead of presenting it modally over the UITabBarController.
Using the UISplitViewControllerDelegate method
- splitViewController:showDetailViewController:sender:
In case the UISplitViewController is collapsed get the masters navigation controller and push the detail view onto this navigation controller:
- (BOOL)splitViewController:(UISplitViewController *)splitViewController
showDetailViewController:(UIViewController *)vc
sender:(id)sender {
NSLog(@"UISplitViewController collapsed: %d", splitViewController.collapsed);
// TODO: add introspection
if (splitViewController.collapsed) {
UITabBarController *master = (UITabBarController *) splitViewController.viewControllers[0];
UINavigationController *masterNavigationController = (UINavigationController *)master.selectedViewController;
// push detail view on the navigation controller
[masterNavigationController pushViewController:vc animated:YES];
return YES;
}
return NO;
}
Upvotes: 8