iOS8 TabbarController inside a UISplitviewController Master
Asked Answered
A

6

9

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?

Appetency answered 30/8, 2014 at 9:35 Comment(0)
P
7

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
    }
Postglacial answered 3/8, 2015 at 22:58 Comment(0)
P
8

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;
}
Personify answered 14/9, 2014 at 10:12 Comment(2)
It seems like this method is never called if your using performSegueWithIdentifier as I do in my tableView:didSelectRowAtIndexPath :/ Any other idea how to solve this?Appetency
Did you set the delegate of the splitcontroller?Personify
P
7

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
    }
Postglacial answered 3/8, 2015 at 22:58 Comment(0)
B
1

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;
}
Blooded answered 9/10, 2014 at 12:9 Comment(0)
B
1

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?

Befool answered 14/7, 2015 at 15:16 Comment(0)
J
1

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.

Ja answered 16/8, 2015 at 22:40 Comment(0)
G
0

Here is an alternative that is based on testing the size classes of the splitViewController :

  1. Use a custom UISplitViewController (subclass)
  2. Override the showDetailViewController operation
  3. Use the traitCollection to determine the class of the UISplitViewController
  4. If the horizontal class is Compact, get the navigationController to call showViewController

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.

Gant answered 12/7, 2015 at 16:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.