How to force a UIViewController to Portrait orientation in iOS 6

106,442

Solution 1

If you want all of our navigation controllers to respect the top view controller you can use a category so you don't have to go through and change a bunch of class names.

@implementation UINavigationController (Rotation_IOS6)

-(BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end

As a few of the comments point to, this is a quick fix to the problem. A better solution is subclass UINavigationController and put these methods there. A subclass also helps for supporting 6 and 7.

Solution 2

The best way for iOS6 specifically is noted in "iOS6 By Tutorials" by the Ray Wenderlich team - http://www.raywenderlich.com/ and is better than subclassing UINavigationController for most cases.

I'm using iOS6 with a storyboard that includes a UINavigationController set as the initial view controller.

//AppDelegate.m - this method is not available pre-iOS6 unfortunately

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;

if(self.window.rootViewController){
    UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
    orientations = [presentedViewController supportedInterfaceOrientations];
}

return orientations;
}

//MyViewController.m - return whatever orientations you want to support for each UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}

Solution 3

This answer relates to the questions asked in the comments of the OP's post:

To force a view to appear in a given oriention put the following in viewWillAppear:

UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
    UIViewController *c = [[UIViewController alloc]init];
    [self presentModalViewController:c animated:NO];
    [self dismissModalViewControllerAnimated:NO];
}

It's a bit of a hack, but this forces the UIViewController to be presented in portrait even if the previous controller was landscape

UPDATE for iOS7

The methods above are now deprecated, so for iOS 7 use the following:

UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
     UIViewController *c = [[UIViewController alloc]init];
     [c.view setBackgroundColor:[UIColor redColor]];
     [self.navigationController presentViewController:c animated:NO completion:^{
            [self.navigationController dismissViewControllerAnimated:YES completion:^{
            }];
     }];
}

Interestingly, at the time of writing, either the present or dismiss must be animated. If neither are, then you will get a white screen. No idea why this makes it work, but it does! The visual effect is different depending on which is animated.

Solution 4

So I ran into the same problem when displaying portrait only modal views. Normally, I'd create a UINavigationController, set the viewController as the rootViewController, then display the UINavigationController as a modal view. But with iOS 6, the viewController will now ask the navigationController for its supported interface orientations (which, by default, is now all for iPad and everything but upside down for iPhone).

Solution: I had to subclass UINavigationController and override the autorotation methods. Kind of lame.

- (BOOL)shouldAutorotate {
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}
// pre-iOS 6 support 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}

Solution 5

IOS 5

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{

    return (interfaceOrientation == UIInterfaceOrientationPortrait);

}

IOS 6

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations{

    //    UIInterfaceOrientationMaskLandscape;
    //    24
    //
    //    UIInterfaceOrientationMaskLandscapeLeft;
    //    16
    //
    //    UIInterfaceOrientationMaskLandscapeRight;
    //    8
    //
    //    UIInterfaceOrientationMaskPortrait;
    //    2

    //    return UIInterfaceOrientationMaskPortrait; 
    //    or
          return 2;
}
Share:
106,442

Related videos on Youtube

Neal
Author by

Neal

Updated on April 13, 2020

Comments

  • Neal
    Neal about 4 years

    As the ShouldAutorotateToInterfaceOrientation is deprecated in iOS 6 and I used that to force a particular view to portrait only, what is the correct way to do this in iOS 6? This is only for one area of my app, all other views can rotate.

  • Wayne Liu
    Wayne Liu over 11 years
    I can confirm this works. You may also replace "[self.viewControllers lastObject]" with "self.topViewController" if you like.
  • phil88530
    phil88530 over 11 years
    doesn't work on mine. I had this code with global setted to all orientations
  • jMelnik
    jMelnik over 11 years
    @aprato do I need to remove the old shouldAutorotateToInterfaceOrientation references from my code?
  • JRG-Developer
    JRG-Developer over 11 years
    @jMelnik If your app is only going to be iOS 6.0+, then yes, I would think you should. However, if you're going to support anything less than iOS 6.0, (5.1 and before), you should not change everything over yet as shouldAutorotate and supportedInterfaceOrientations are only iOS 6.0+.
  • Borut Tomazin
    Borut Tomazin over 11 years
    If you are using UITabBarController than this UINavigationController category is no help. You should make category on UITabBarController instead...
  • Lope
    Lope over 11 years
    Problem with this solution is that it doesn't work when you pop controller that was in landscape and your new top controller supports only portrait (or vice versa), those callbacks are not called in this case and I am yet to find way how to force new top controller into correct orientation. Any ideas?
  • Anthony
    Anthony over 11 years
    @Lope have you made sure your nav controller is root to the key window? Which of the new rotation methods have you implemented?
  • Lope
    Lope over 11 years
    I subclassed UINavigationController and set it as window.rootController. I implemented all 3 methods, it works great when you change rotation of device, problem is that those methods (and nothing related to rotation) is called when you pop view controller
  • tomwhipple
    tomwhipple over 11 years
    supportedInterfaceOrientations should return an NSUInteger, not BOOL. See developer.apple.com/library/ios/#featuredarticles/…
  • otakuProgrammer
    otakuProgrammer over 11 years
    its worked, for me its the tabbarcontroller, again thanks for the answer
  • Pranav Jaiswal
    Pranav Jaiswal over 11 years
    @aparto could u please answer my question, I followed your answer for the current question during implementation. stackoverflow.com/questions/13325801/…
  • Dr4ke the b4dass
    Dr4ke the b4dass over 11 years
    FWIW, I had to go this route as well... Nothing else worked. Thanks.
  • toblerpwn
    toblerpwn over 11 years
    @Lope - Same exact issue here. Have you found anything? Supremely lame that Apple forces this design on every app imho.
  • Lope
    Lope over 11 years
    @toblerpwn - sadly, I did not. I was forced to abandon landscape orientation and my apps now work only in portrait
  • Alex
    Alex over 11 years
    Excellent! Need to be maximally at the top of this thread. Because it is the most simple way to solve problem
  • Rafael Nobre
    Rafael Nobre over 11 years
    I thought doing this myself, but seeing UIViewController defines those methods in categories itself, it should be safer to override them in subclasses. Also it does not cover the case when you push/pop/present a portrait only VC from a landscape one.
  • Tariq
    Tariq over 11 years
    If I am doing push or pop from landscape view controller then this force UIViewController changes into Landscape. However if I rotate into portrait then it works fine and it will never changed into landscape. The only problem while push or pop from landscape. Please help
  • Craig Watkinson
    Craig Watkinson about 11 years
    @lope see my answer below regarding forcing portrait
  • Craig Watkinson
    Craig Watkinson about 11 years
    @toblepwn see my answer below regarding forcing portrait
  • Lope
    Lope about 11 years
    Thanks, I will give it a try when I find few minutes of free time
  • arsenius
    arsenius about 11 years
    The first of these crashes for me regardless of iOS version. Says dismiss should not be called before present has finished.
  • Rafael Nobre
    Rafael Nobre about 11 years
    @arsenius Can you post a snippet of how you're using it ? As long as it isn't animated it shouldn't have the issue you mention
  • arsenius
    arsenius about 11 years
    I also put the second snippet into viewDidAppear and it does nothing to help my situation on iOS 6. Question is here: stackoverflow.com/questions/15654339/…
  • arsenius
    arsenius about 11 years
    Sorry, one last comment here. Moving the iOS 5 code to viewDidAppear creates some sort of infinite loop with this output: -[UIApplication beginIgnoringInteractionEvents] overflow. Ignoring.
  • Karthik
    Karthik about 11 years
    @Roshan Jalgaonkar In ios 6 It does not work for me i need only portrait with down home button how can i set this UIOrientation....
  • Homam
    Homam almost 11 years
    This is best solution for iOS 6
  • danes
    danes almost 11 years
    @RohanAgarwal it does work as advertised, I'm using it here. But you need to have the accepted answer's code implemented as well, or it won't work.
  • danes
    danes almost 11 years
    Has anyone figured out how to make this work with the correct rotation animation at the same time? It's a little jarring to see it switch from portrait to landscape without the animation. It works, just hoping to make it work a little better.
  • Kirti Nikam
    Kirti Nikam almost 11 years
    @Phil, Its works fine for iOS 6. But in some cases, like if you go from landscape to portrait then it doesn't work. Any idea why it happens?
  • Alejandro Iván
    Alejandro Iván almost 11 years
    @Karthik you have to enable supported rotations in your App's target for this to work.
  • oscar castellon
    oscar castellon over 10 years
    Very usefull solution. For me, the best.
  • Kalpesh
    Kalpesh over 10 years
    @Craig Watkinson It is not working in storyboard. and presentModalViewController and dismissModalViewControllerAnimated is deprecated if iam using presentVirecontroller then it wont work .please help me
  • Martin Berger
    Martin Berger over 10 years
    Working on iOS 7 beta 6. Works when going from landscape to portrait in my case.
  • Marcel Marino
    Marcel Marino over 10 years
    I'm in iOS 6 but this doesn't work. It breaks on the "UIViewController *presentedViewController" line.
  • The iCoder
    The iCoder over 10 years
    @BorutTomazin I have tabBarController having navigationControllers on each tab then What will be the solution? Any help will be appreciated.
  • iCode
    iCode over 10 years
    @Craig Watkinson Thanks for your great answer, working perfect!
  • Aaron
    Aaron about 10 years
    I tried so many other solutions, but this is the only one that worked for me. It works great in iOS 6 & iOS 7 and was relatively easy to implement compared with other proposed solutions.
  • Nick
    Nick about 10 years
    @Lope Over three months later and still no fix for this. Anyone? Anyone??
  • Nick
    Nick about 10 years
    This doesn't work for me. When rotating from portrait to landscape (or vice versa) on a viewController that only supports portrait, it 'locks' all the other viewControllers that support both portrait AND landscape.
  • maddy
    maddy about 10 years
    thanks it worked, dont know whats going to happen if apple change some thing in its api, have given around two days but can not solve problem of pushing a view in portrait from landscape in navigation based app.
  • Muhammad Rizwan
    Muhammad Rizwan over 9 years
    its about particular view controller not for whole application.
  • Alexey
    Alexey over 9 years
    For ios8 dismissViewControllerAnimated just crashes. I found that calling [NWSAppDelegate sharedInstance].window.rootViewController = nil; [NWSAppDelegate sharedInstance].window.rootViewController = previousRootController works nice.
  • AlexanderN
    AlexanderN over 9 years
    @Alexey Its not crashing in iOS8 for me.
  • Hitarth
    Hitarth over 9 years
    @Craig Watkinson its working fine when i Push VC from landscap. but when i popview from landscap its crashing. Reason : 'preferredInterfaceOrientationForPresentation must return a supported interface orientation!' Please help me out on this.
  • Gary Wright
    Gary Wright about 9 years
    This is the only solution I could get to work on IOS8
  • Noundla Sandeep
    Noundla Sandeep about 9 years
    @Lope, It has been a year now. Did you get a proper solution for this? I have the same issue.
  • Lope
    Lope about 9 years
    @noundla I don't think I did, I change the design of the app so that I don't need it and then forgot about the issue. It's just not worth my nerves to work around questionable Apple's design decisions
  • Ivan Lesko
    Ivan Lesko over 8 years
    Simplest solution. Confirmed it works on iOS 9 with swift 2.0