Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UINavigationController inside a UITabBarController inside a UISplitViewController presented modally on iPhone

I'm having a UISplitViewController that contains a UITabBarController as master view. This UITabBarController contains a UINavigationController. The detail view contains a UINavigationController as well.

Storyboard

On the iPad this works as expected. The show detail segue presents the imageview within the navigation controller on the detail view.

On the iPhone on the other hand I expected that the show detail segue pushes the detail view on the stack of the navigation controller of the master view. But actually it is presented modally over the master view.

When removing the UITabBarController from the storyboard and using the UINavigationController directly in the master view this works.

Has anybody an idea how I could present the detail view on the stack of the master's UINavigationController on an iPhone?

like image 620
Peter Oettl Avatar asked Sep 14 '14 09:09

Peter Oettl


2 Answers

The problem with Peter's solution is that it will fall apart with the iPhone 6 +. How so? With that code, if an iPhone 6 + is in portrait orientation - the detail view pushes onto the navigation stack. All is well, so far. Now, rotate into landscape, and then you'll have the detail view showing as the detail view and the master view.

You'll need the split view controller's delegate to implement two methods:

- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)detailVC sender:(id)sender
{
    UITabBarController *masterVC = splitViewController.viewControllers[0];

    if (splitViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact)
        [masterVC.selectedViewController showViewController:detailVC sender:sender];
    else
        [splitViewController setViewControllers:@[masterVC, detailVC]];

    return YES;
}

And now, you'll need to return the top view controller from the selected tab's navigation controller:

- (UIViewController*)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController
{
    UITabBarController *masterVC = splitViewController.viewControllers[0];

    if ([(UINavigationController*)masterVC.selectedViewController viewControllers].count > 1)
        return [(UINavigationController*)masterVC.selectedViewController popViewControllerAnimated:NO];
    else
        return nil; // Use the default implementation
}

With this solution, everything pushes onto the navigation stack when it should and also updates the detail view correctly on the iPad/6+ landscape.

like image 178
Dreaming In Binary Avatar answered Sep 28 '22 03:09

Dreaming In Binary


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];
        // push was not always working (see discussion in answer below), use showViewController instead
        [masterNavigationController showViewController:vc sender:sender];

        return YES;
    }

    return NO;
}
like image 39
Peter Oettl Avatar answered Sep 28 '22 03:09

Peter Oettl