Search code examples
cocoa-touchiosuinavigationcontrollerrotationuisplitviewcontroller

UISplitViewController stops auto-rotating after trying to use the UINavigationController inside of it


I've been having a bit of trouble with a UISplitViewController in my iPad app. I am attempting to make a simple navigation tree using the UINavigationController inside of the UISplitView. I have used the following basic code to do this:

NavController.h

@interface NavController : NSObject {
    /* 
     * This is connected properly to the UINavigationController in the 
     * UISplitViewController through Interface Builder.
     */

    UINavigationController *navigationController;

 }

 @property (nonatomic, retain) IBOutlet UINavigationController *navigationController;

 @end

NavController.m

#import "NavController.h"

@implementation NavController

@synthesize navigationController;

- (void) awakeFromNib {
    UIViewController *testController = [[UIViewController alloc] init];
    UITableView *tableView = [[UITableView alloc] init];

    [testController setView: tableView];

    [navigationController pushViewController: testViewController
                                    animated: YES];

}

@end

This code successfully pushes the view to the navigation controller, and I can navigate back with the back button, however, my problem arises with the fact that after this happens, my UISplitViewController no longer auto-rotates or rotates at all from the portrait position. When I remove this code (and the view does not get pushed) it works as expected.

What am I doing wrong, and am I going about this in the right way?


Solution

  • This drove me absolutely nuts too. I did a couple of things that made it work, but I'm not happy about my solutions -- 1) I don't really understand it and 2) it seems hacky.

    I added this to my app delegate (my .m file):

    @interface UITabBarController (MyApp)
    @end
    
    @interface UINavigationController (MyApp)
    @end
    
    @implementation UITabBarController (MyApp) 
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
        return YES;
    }
    @end
    
    @implementation UINavigationController (MyApp) 
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
        return YES;
    }
    @end
    

    This worked for the most part. For the views that didn't auto-rotate though, I had to manually rotate the views myself using transforms. I did something like:

    - (void)deviceOrientationDidChangeWithAnimation:(BOOL)animated {
        UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    
        if (orientation == oldOrientation) {
            return;
        }
    
        if (animated) {
            CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
            [UIView beginAnimations:nil context:nil];
            [UIView setAnimationDuration:duration];
            [UIView setAnimationDidStopSelector:@selector(orientationChanged)];
        }
    
        [self sizeToFitOrientation:YES];
    
        if (animated) {
            [UIView commitAnimations];
        }
    
        oldOrientation = orientation;
    }
    
    - (CGAffineTransform)transformForOrientation {
        UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
        if (orientation == UIInterfaceOrientationLandscapeLeft) {
            return CGAffineTransformMakeRotation(M_PI*1.5); // rotated CCW
        } else if (orientation == UIInterfaceOrientationLandscapeRight) { // CW
            return CGAffineTransformMakeRotation(M_PI/2);
        } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { // CCW
            return CGAffineTransformMakeRotation(-M_PI);
        } else { // CW
            return CGAffineTransformIdentity;
        }
    }
    
    - (void)sizeToFitOrientation:(BOOL)transform {
        if (transform) {
            self.view.transform = CGAffineTransformIdentity;
        }
    
        CGRect frame = [UIScreen mainScreen].applicationFrame;
        CGPoint center = CGPointMake(frame.origin.x + ceil(frame.size.width/2), frame.origin.y + ceil(frame.size.height/2));
    
        CGFloat width = frame.size.width - 0 * 2;
        CGFloat height = frame.size.height - 0 * 2;
    
        UIInterfaceOrientation _orientation = [UIApplication sharedApplication].statusBarOrientation;
        if (UIInterfaceOrientationIsLandscape(_orientation)) {
            self.view.frame = CGRectMake(0, 0, height, width);
        } else {
            self.view.frame = CGRectMake(0, 0, width, height);
        }
        self.view.center = center;
    
        if (transform) {
            self.view.transform = [self transformForOrientation];
        }
    }
    

    Hope this helps! And if someone can point out mistakes I've made (or bad things I'm perpetuating), I'd be happy to learn. :)