iOS 6 - Navigation Controller Landscape Rotations For Some Views While Others Portrait Only
Asked Answered
I

2

3

I am building an app that will be Portrait only for the main views (Both normal and upside down). I have set this setting in the Project Settings/Plist and all works fine. However, I have a few modal views that do things like display images/videos, and I want them to be able to rotate to ALL orientations.

I tried adding a category for UINavigationController but no luck. I have also added to the viewController that calls the modal the below code:

-(BOOL)shouldAutomaticallyForwardAppearanceMethods{
    return NO;
}
-(BOOL)shouldAutomaticallyForwardRotationMethods{
    return NO;
}

I have added the below code to the modal viewControllers that I want to allow all orientations:

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAll;
}

What am I missing? Any suggestions?

Incapable answered 20/2, 2013 at 20:32 Comment(0)
L
3

On iOS 6, rotation handling has changed. For the problem you described, there are several approaches. First, in the plist, enable all orientations except portrait upside down.

Then you could use one of the following solutions:

  1. Use a subclass of UINavigationController that does only allow rotation to portrait.
  2. For all controllers specify which rotations they support.
  3. You can override a method in your application delegate. As that method is called on your delegate whenever the orientation changes or a new view controller is pushed, you can use it to temporarily enable/disable landscape display for your app:

    // In AppDelegate.h:
    @property (nonatomic) BOOL portraitOnly;
    
    // In AppDelegate.m:
    - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
    {
        return _portraitOnly ? UIInterfaceOrientationMaskPortrait : UIInterfaceOrientationMaskAllButUpsideDown;
    }
    
    // to switch to portrait only:
    ((AppDelegate *)[UIApplication sharedApplication].delegate).portraitOnly = YES;
    
    // to switch to allowing landscape orientations:
    ((AppDelegate *)[UIApplication sharedApplication].delegate).portraitOnly = NO;
    
Loyce answered 25/4, 2013 at 10:44 Comment(5)
This is terrible idea. Different parts of your app setting the app as portrait only or not can lead to bugs and things hard to track down. You should make that method return all the orientations that the app supports at some point, and have each VC implement its own -supportedOrientations methodSophist
@JavierSoto That's the reason why it's the third of three solutions I proposed. The first two are better. I listed all three so that the author of the question can choose the one most fitting for the problem at hand.Loyce
This doesn't seem to work if you push B onto A, where A is portrait and B is landscape. The UINavigationController only seems to care about the root's orientation, so subsequent view controllers don't have their preferred orientation honored. Was this your experience?Lawler
@Lawler As far as I know, there is no good way of forcing a navigation controller to change its orientation on push. I think it would also be highly surprising when the interface suddenly rotates on push.Loyce
@Lawler which approach finally you have used I have similar problem and tried a lot ways but none of them working for me. Just stuck with this issue. Any help will be appreciated.Aeniah
M
1

You need to enable rotation for the viewControllers that are ancestors in the hierarchy in your build settings (in order to allow the VC's lower in the hierarchy to be able to rotate if they want to). And then return the proper logic from shouldAutoRotate, supportedInterfaceOrientations,and willAnimateRotationToInterfaceOrientation in each viewController.

-Return NO from shouldAutoRotate for the viewControllers that do not move at all.

-And likewise, return YES from shouldAutoRotate and return the orientations valid in that VC from supportedInterfaceOrientations

-Use willAnimateRotationToInterfaceOrientation to do any last minute cleanup or data changes you need to do before the new orientation appears.

Feel free to let me know if your still having trouble. Hope it helps!

Microscopium answered 20/2, 2013 at 20:47 Comment(9)
Thanks for the help. So I enabled all orientations, then tried just manually setting the 'supportedInterfaceOrientations' in the views I don't want to rotate to landscape, and they still rotate! I tried both yes/no for 'shouldAutoRotate' as well in those views with no difference.Incapable
-(BOOL)shouldAutorotate { return NO; } -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationPortrait; }Microscopium
Put that in your view and see if it rotates. That's the exact code i use in a project where one vc doesn't rotate but others doMicroscopium
That is what I had already put in the view that I don't want rotating. It still rotates to all orientations.Incapable
What's the view that you are in? Is it embedded in a navigation or tab bar?Microscopium
It is the root view, embedded in a navigation controller.Incapable
That's your problem right there. Since it is embedded in the navigation controller, its not actually the highest in the ancestral hierarchy. You need to override the class for the navigationController that it is embedded in, and return that code above inside of that class as well. You'll be good to go then.Microscopium
Even if you do this in UINavigationController, this one doesn't check for the new orientations supported by the controller you're pushing, so it doesn't rotate itself when pushing a VC.Sophist
Our experience echos what @JavierSoto said. This doesn't seem to work if you push B onto A, where A is portrait and B is landscape. The UINavigationController only seems to care about the root's orientation, so subsequent view controllers don't have their preferred orientation honored. Was this not your experience?Lawler

© 2022 - 2024 — McMap. All rights reserved.