46

In iOS 5 we could change the device orientation programmatically like so:

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];

But in iOS 6 setOrientation is deprecated, how may i change the device orientation programmatically in iOS 6?

Ricardo Sanchez-Saez
  • 9,466
  • 8
  • 53
  • 92
uttam
  • 1,364
  • 4
  • 20
  • 35

15 Answers15

49

Here are my "five cents", tested on iOS7 with ARC

[[UIDevice currentDevice] setValue:
                      [NSNumber numberWithInteger: UIInterfaceOrientationPortrait]
                            forKey:@"orientation"];

This doesnt generate "leak" warning as performSelector will.

UIAlertView - with this code, when you open UIAlertView during view(will/Did)appear you will notice that all but this view is in portrait (apple, really?) I wasn't able to force the view to reorient but found that if you put slight delay before opening the UIAlertView then view has time to change orientation.

Note I'm releasing my app week commencing 12/09/2014 and I will update post if it will pass or fail.

Lukasz 'Severiaan' Grela
  • 6,078
  • 7
  • 43
  • 79
20

This does not answer how to change the device Orientation, but an additional information that might help you.

iOS 6 UI Interface Orientation - shouldAutorotateToInterfaceOrientation: Not Working

The method shouldAutorotateToInterfaceOrientation: is NOT supported in iOS 6. Its deprecated. Just in case if you are a newbie, who just stared working in cocoa, and wondering why is your view controller messed up in iOS 6 and perfect in iOS 5, just know that shouldAutorotateToInterfaceOrientation: is not supported anymore. Even though it may work well with Xcode 4 to 4.3 it will NOT work on Xcode 4.5.

Apple provides a new method to get this thing done, in a much cleaner fashion. You use supportedInterfaceOrientations instead. It returns all of the interface orientations that the view controller supports, a mask of interface orientation values.

UIInterfaceOrientationMask Enum:

These constants are mask bits for specifying a view controller’s supported interface orientations.

typedef enum {
    UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
    UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
    UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
    UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
    UIInterfaceOrientationMaskLandscape =
        (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
    UIInterfaceOrientationMaskAll =
        (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |
    UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
    UIInterfaceOrientationMaskAllButUpsideDown =
        (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |
    UIInterfaceOrientationMaskLandscapeRight),
} UIInterfaceOrientationMask;

Using shouldAutorotateToInterfaceOrientation: method:

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return UIInterfaceOrientationIsLandscapeRight(toInterfaceOrientation);
}

Using supportedInterfaceOrientations method:

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

These are the added methods to UIViewController regarding Orientation in iOS6

  1. UIViewController preferredInterfaceOrientationForPresentation

  2. UIViewController shouldAutorotate

  3. UIViewController supportedInterfaceOrientations

Added methods to UIApplication regarding Orientation in iOS6

  1. UIApplication supportedInterfaceOrientationsForWindow:

  2. UIInterfaceOrientationMask

Bala
  • 2,895
  • 1
  • 19
  • 60
  • 3
    Thanks for your ans but i want to change the orientation programmatically.How I can change the orientation like we were doing in ios5 using [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight]; – uttam Sep 29 '12 at 09:38
  • this is my issue @Bala http://stackoverflow.com/questions/15563614/not-able-to-show-the-image-in-proper-format-from-camera-in-landscape-mode – Goutham Mar 26 '13 at 06:19
  • 4
    -1 this does not answer the question of how to change the device orientation programatically. – Justin Tanner Nov 20 '13 at 23:04
  • 2
    That's not the answer to the question. That's more like additional information. – alper_k Sep 08 '14 at 12:45
20

I found out that the easiest way to force the device to change orientation is to present a new view controller (using presentViewController:animated:completion:) where the new view controller specified a particular preferred orientation (by implementing the method -(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation).

When a new view controller is presented, as expected, the orientation will change to the one preferred by the new view controller. So, simplest implementation (best practice?) will be to embed all functionality you needed in a specific orientation into a separate view controller, and present it as needed. The system will take care of changing the orientation for you.

Obviously this might not suit all use cases, but, fortunately the same trick is applicable to force the device to change orientation for existing view controller.

The trick is to present a new view controller with the specific preferred orientation that you needed, and then hide it immediately. This will cause the orientation to change temporary when the new view controller is presented. The best part is, when the new view controller is dismissed, the original (presenting) view controller's preferredInterfaceOrientationForPresentation is queried again, you can specify the final orientation you want here.

One important thing to look out here is to also temporary disable auto rotation in the original view controller (when coming back from the newly presented-then-dismissed view controller), so that when user rotate their phone towards the new orientation, it does not triggered further auto rotation.

The following code should illustrate my point, my example forces rotation to portrait, just change accordingly if you want other orientation.

Assuming you have the original view controller named Original, and a temporary view controller named ForcePortrait

@interface Original : UIViewController
{
    BOOL orientationToPortrait; //should set to NO by default
}
@end

@implementation Original
- (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation
{
    if(orientationToPortrait)
    {
        //when we manually changed, show in Portrait
        return UIInterfaceOrientationPortrait;
    }
    else
    {
        //before manual orientation change, we allow any orientation
        return self.interfaceOrientation;
    }
}

-(BOOL) shouldAutorotate
{
    //we should 'lock' the rotation once we manually change it
    return !orientationToPortrait;
}

-(void) changeOrientationToPortrait
{
    //Sample method to change the orientation
    //when called, will show (and hide) the temporary view
    //Original.preferredInterfaceOrientationForPresentation will be called again after this method

    //flag this to ensure that we tell system we prefer Portrait, whenever it asked again
    orientationToPortrait = YES;

    //presenting the following VC will cause the orientation to temporary change
    //when the new VC is dismissed, system will ask what is our (Original) orientation preference again
    ForcePortrait* forcePortrait = [[ForcePortrait alloc] init];
    [self presentViewController:forcePortrait animated:NO completion:^{
        [forcePortrait dismissViewControllerAnimated:NO completion:nil];
    }];
}


@end

@interface ForcePortrait : UIViewController
@end

@implementation ForcePortrait
- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}
@end
P.L.
  • 1,498
  • 14
  • 18
  • Very elegant solution. Works perfectly on iOS 7 for me ! – Nico Mar 06 '14 at 02:08
  • 1
    A great solution except if I try and pop to any view controller from the parent view controller it fails. – hokiewalrus Apr 28 '14 at 21:01
  • Is there any way to force this change to be animated? I am pushing a image picker controller pulling from the gallery (camera roll) and it non-animatedly rotates the status bar and nothing else in my view before animating the new view controller's transition in. – Dennis L Oct 05 '15 at 14:16
10

Try this:

#import <objc/message.h>

if(UIDeviceOrientationIsLandscape(self.interfaceOrientation)){
        if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)])
        {
            objc_msgSend([UIDevice currentDevice], @selector(setOrientation:), UIInterfaceOrientationPortrait );
        }
    }
Sergey K.
  • 24,894
  • 13
  • 106
  • 174
Bissy
  • 131
  • 3
  • 2
    +1 for this option. Probably would get rejected by Apple, but it was what I needed for an enterprise app. – Austin Nov 28 '12 at 16:07
  • it works perfectly! But after it hidden status bar becomes visible. – nesimtunc Mar 04 '13 at 15:19
  • 1
    @JustinTanner It does indeed work in iOS 7. You don't need #import though. – Jared Price May 08 '14 at 17:06
  • It worked in development environment for IOS7.1 However, when I deployed to App Store, this does not work in IPhone5s Any guesses? – srcnaks Jun 02 '14 at 08:04
  • 1
    This is not a good practice and it does not follow the Apple guidelines - it is curios that your app was not rejected because of using private libraries. I used it just for in-house development. – Bissy Jun 02 '14 at 14:45
  • @Bissy, This does not work for iOS 7.1.1 for iPad Air. Though works perfect in iPad 3 iOS 7.1.1. Any particular reason/explanation for this. – Meet Jun 30 '14 at 17:38
5

You should place
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
in your AppDelegate didFinishLaunchingWithOptions Method.

Then, anywhere in your application you can get the current orientation with:

UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

And test orientation with:

UIInterfaceOrientationIsPortrait(orientation) 
UIInterfaceOrientationIsLandscape(orientation)

as, like

if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
{
    // code for landscape orientation
     // OR
    [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
     //  OR
    [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];

}
else if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation))
{
    // code for Portrait orientation
    //  OR
   [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortraitUpsideDown];
    //  OR
   [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
}
iPatel
  • 46,010
  • 16
  • 115
  • 137
  • Awesome! There was no need for `beginGeneratingDeviceOrientationNotifications` prior to iOS6, but now you need this extra line. Thanks a ton! – borisdiakur Oct 25 '12 at 11:40
  • 3
    `Receiver type 'UIDevice' for instance message does not declare a method with selector 'setOrientation:'` – matt Apr 05 '13 at 03:13
  • What's the purpose of `[[UIDevice currentDevice] setOrientation:]` Doesn't the device automatically set it's own orientation when the device is rotated? – zakdances Apr 06 '13 at 22:46
  • Looking for solution whole week and only this code finally works! Especially on iPad with camera preview and landscape orientated device is almost impossible force app to orient portrait. Thanks for answer! – Benny7500 May 02 '13 at 20:36
  • Looks messy to me. The UIDevice orientation property is readonly. Even so, this is trying to set UIDevice orientation property using UIInterfaceOrientation values. – Jeff May 27 '13 at 22:20
  • It's showing warning : "Implicit conversion from enum type to different enum type"...? – Jayprakash Dubey Feb 04 '14 at 14:23
4

This code is for iOS 8 or later

NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
Pang
  • 9,564
  • 146
  • 81
  • 122
RAUL QUISPE
  • 800
  • 9
  • 13
  • I wrote same code and its working properly but If I am using [NSNumber numberWithInt: UIInterfaceOrientationLandscapeRight] then it is also rotating in same direction (anti clock wise). I want left to Right rotation (rotation in clock wise direction). – Dipak Apr 30 '18 at 12:18
  • Should not be used, this is apple private API - once they will change orientation string to anything else your app will crash. – XcodeNOOB Oct 21 '18 at 11:56
2

Apple made changing the device orientation programmatically in quite difficult (on purpose mind you).

As far as I know the only way to accomplish what you're asking is to simulate the change of device orientation.

Using setTransform to rotate the UIView and re-applying its own frame gives the desired results.

[YourView setTransform:CGAffineTransformMakeRotation(1.57)];
[YourView setFrame:CGRectMake(0, 0, YourView.frame.size.width, YourView.frame.size.height)];

And when the device physical orientation changes we can undo the transformation.

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [YourView setTransform:CGAffineTransformMakeRotation(0)];
    [YourView setFrame:CGRectMake(0, 0, YourView.frame.size.width, YourView.frame.size.height)];
}
Aleksander Azizi
  • 9,829
  • 9
  • 59
  • 87
2

Try this...It worked out for me...

UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview]; [window addSubview:view];
ggrana
  • 2,335
  • 2
  • 21
  • 31
2

@implementation UINavigationController (autorotate)

 -(NSUInteger)supportedInterfaceOrientations
 {
   //make the check for iphone/ipad here

    if(IPHONE)
    {
      return UIInterfaceOrientationMaskPortrait;
    } 
    else
    {
      return UIInterfaceOrientationMaskLandscape;
    }
 }

 - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
 {
    return UIInterfaceOrientationPortrait;
 }

 - (BOOL)shouldAutorotate
 {
    return NO;
 }
Kumar KL
  • 15,315
  • 9
  • 38
  • 60
Muhammad Shauket
  • 2,643
  • 19
  • 40
2

A little modification to Bissy's answer, if you want to avoid using Runtime Library:

if (UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]))
{
    if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)])
    {
        int orientationPortrait = UIInterfaceOrientationPortrait;
        NSMethodSignature *sig = [[UIDevice currentDevice] methodSignatureForSelector:@selector(setOrientation:)];
        NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sig];
        [invo setTarget:[UIDevice currentDevice]];
        [invo setSelector:@selector(setOrientation:)];
        [invo setArgument:&orientationPortrait atIndex:2];
        [invo invoke];
    }
}
Perisheroy
  • 239
  • 4
  • 8
2

This works for iOS7, force autorotate to portrait.

//In your viewController.m
#import <objc/message.h>

// for autorotate viewController to portraid
- (void)viewWillAppear:(BOOL)animated {
    UIInterfaceOrientation orientationStatusBar =[[UIApplication sharedApplication] statusBarOrientation];
    switch (orientationStatusBar) {
        case UIInterfaceOrientationPortrait:break;
        case UIInterfaceOrientationLandscapeLeft:
            objc_msgSend([UIDevice currentDevice], @selector(setOrientation:), UIInterfaceOrientationPortrait);
            break;
        case UIInterfaceOrientationLandscapeRight:
            objc_msgSend([UIDevice currentDevice], @selector(setOrientation:), UIInterfaceOrientationPortrait);
            break;
        default:
            break;
    }
}

// this permit autorotate
- (BOOL) shouldAutorotate
{
   // this lines permit rotate if viewController is not portrait
    UIInterfaceOrientation orientationStatusBar =[[UIApplication sharedApplication] statusBarOrientation];
    if (orientationStatusBar != UIInterfaceOrientationPortrait) {
        return YES;
    }
    //this line not permit rotate is the viewController is portrait
    return NO;
}

NOTE: I implemented this option in my app, but probably would get rejected by Apple (comment for Austin for edited 6 of Sergey K. in oct 2012).

krsteeve
  • 1,794
  • 4
  • 19
  • 29
ppVen
  • 21
  • 3
1
if (self.interfaceOrientation != UIInterfaceOrientationLandscapeRight) {
// http://stackoverflow.com/questions/181780/is-there-a-documented-way-to-set-the-iphone-orientation
// http://openradar.appspot.com/radar?id=697
// [[UIDevice currentDevice] setOrientation: UIInterfaceOrientationLandscapeRight]; // Using the following code to get around apple's static analysis...
[[UIDevice currentDevice] performSelector:NSSelectorFromString(@"setOrientation:") withObject:(id)UIInterfaceOrientationLandscapeRight];
}
n00bProgrammer
  • 4,261
  • 3
  • 32
  • 60
0
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{
    // Return YES for supported orientations
   return NO;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
   return  interfaceOrientation == UIInterfaceOrientationPortrait
           || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown ;
}
ganesh
  • 780
  • 7
  • 19
0

This works for me on Xcode 6 & 5.

- (BOOL)shouldAutorotate {return YES;}
- (NSUInteger)supportedInterfaceOrientations {return (UIInterfaceOrientationMaskPortrait);}
SamSmart
  • 355
  • 3
  • 3
0

Its interesting how others didn't run to problems after not setting it like this :

+ (void)setOrientation:(UIDeviceOrientation)orientation {
    [UIDevice.currentDevice setValue:@(orientation) forKey:@"orientation"];
    [UIViewController attemptRotationToDeviceOrientation];
    [UIDevice.currentDevice setValue:@(UIDeviceOrientationUnknown) forKey:@"orientation"];
}

My requirement was to be able to force orientation and then again rotate to device natural orientation... there is UIDeviceOrientationDidChangeNotification that can get you de information to witch orientation to rotate device back but actually it will partly not work if you don't set to unknown immediately after you changed orientation in UIDevice, also there are more details to make it cool but will leave it, as it is out of context of this simple question.

Renetik
  • 5,887
  • 1
  • 47
  • 66