views:

604

answers:

3

My app has about 10 different UIViewControllers, just one of which I want to switch to landscape mode if the device is rotated. (All the rest, I want to keep in portrait.)

In order to implement rotation on that one view, I needed to implement its controller's 'shouldAutorotate' method and return YES. Since this view is accessed via a navigation controller, I also needed to create a subclass of UINavigationController that implements 'shouldAutorotate' and return YES.

This solution works, but too well. I find that all of the UIViewControllers I push onto my subclass of UINavigationController respond to rotation, even if I implement 'shouldAutorotate' and return NO. (Remember: I only want one particular UIViewController to respond to rotation, not every one in the navigation controller's stack.)

So, my question is: how do I best do this? All the solutions I can come up with seem 1) cumbersome, and 2) worse, don't seem to work.

Thanks very much.

A: 

I have seen examples using the way you are doing it but couldn't get it to work properly. I found the better way to do it from Apples examples. Basically you implement a presentModalViewController and create another view. UIKit does a basic rotation animation and fades between the view. You have to implement the rotated view as a delegate class so it can call back to its calling class to dismiss it and update the orientation.

- (void)orientationChanged:(NSNotification *)notification
{
    // We must add a delay here, otherwise we'll swap in the new view
    // too quickly and we'll get an animation glitch
    NSLog(@"orientationChanged");
    [self performSelector:@selector(updateLandscapeView) withObject:nil afterDelay:0];
}

And then to display a landscape screen:

- (void)updateLandscapeView
{
PortraitView *portraitView = [[PortraitView alloc] init];
portraitView.delegate = self;
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView)
{
    [self presentModalViewController: portraitView animated:YES];
    isShowingLandscapeView = YES;
    }
else if (deviceOrientation == UIDeviceOrientationPortrait && isShowingLandscapeView)
{
    [self dismissModalViewControllerAnimated:YES];
    isShowingLandscapeView = NO;
    }
[portraitView release];
}
Rudiger
A: 

I do this by having a root view controller (this could be a UITabBarController) and in it's viewDidLoad method i subscribe to rotation events:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(didRotate:)
                                                      name:@"UIDeviceOrientationDidChangeNotification" 
                                                      object:nil];

Then in the didRotate: method i look at which view controller is visible when the rotation happened, and what orientation the phone is in:

  • (void) didRotate:(NSNotification *)notification {
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

    /* DEVICE JUST ROTATED TO PORTRAIT MODE

    orientation == UIDeviceOrientationFaceUp || orientation == UIDeviceOrientationFaceDown

    */ if(orientation == UIDeviceOrientationPortrait) {

    /* DEVICE JUST ROTATED TO LANDSCAPE MODE */ }else if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {

    }

    }

Within that didRotate: you can look at which is the visible viewController and do what you want from there.

I present a modal view controller in landscape mode when a particular view controller is visible and the phone is rotated into landscape. If any other view controller is visible, i ignore the event.

I force my modal view controller to display in landscape mode in its viewWillAppear method - i can give anyone this code if they want it.

Hope this helps.

Dave

bandejapaisa
A: 

Concise advice from this StackOverflow post.

petert