19

My application is primarily portrait, however there is one view that REQUIRES a landscape orientation.

My views are contained within a UINavigationController, which (apparently) is the cause of this issue.

All UIViewControllers except one have this:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

The UIViewController that requires Landscape has this:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

Now, what happens is when the user reaches the landscape UIViewController, it is shown in portrait. The user can then rotate their phone and it displays in landscape as I want it to (locking to landscape). The user then progresses onwards to a portrait UIViewController and the same happens: it start in landscape, then they rotate their phone and it becomes portrait again (and locks to portrait).

It seems orientation locking is allowed between UIViewControllers, however auto-rotation / programmatically changing the orientation is somehow blocked.

How do I force the phone to update to the correct orientation?

There is a temporary solution: I can detect the orientation of the device and show a message asking them to rotate the device if it is not correct, however this is not optimal.

Zac Altman
  • 1,215
  • 4
  • 25
  • 37

3 Answers3

26

I had the same requirement for one of my applications!!!

luckily I found a solution!

In order to keep main viewcontroller landscape, no matter from what orientation it was popped/pushed, I did the following thing: (in viewWillAppear:)

//set statusbar to the desired rotation position
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];

//present/dismiss viewcontroller in order to activate rotating.
UIViewController *mVC = [[[UIViewController alloc] init] autorelease];
[self presentModalViewController:mVC animated:NO];
[self dismissModalViewControllerAnimated:NO];

P.S.Tested on sdk 3.2.5 ios 5.0.1.

P.S. On iOS 8 previous answer results some screen flickering and also - it is not stable (In some cases It does not work for me anymore.) So, for my needs, I changed the code to: (ARC)

//set statusbar to the desired rotation position
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];

[self.navigationController presentViewController:[UIViewController new] animated:NO completion:^{
    dispatch_after(0, dispatch_get_main_queue(), ^{
        [self.navigationController dismissViewControllerAnimated:NO completion:nil];
    });
}];

//I added this code in viewDidDissapear on viewController class, which will be popped back.

Hopefully it will help!

Guntis Treulands
  • 4,764
  • 2
  • 50
  • 72
  • Works on iOS6beta1. Thank you! – k06a Jun 17 '12 at 11:21
  • For me, with `UINavigationController`, this approach fails because although status bar do rotates, interface still remains. So user must rotate it once more to set the interface. – Martin Berger Jan 08 '13 at 15:14
  • Yes, I myself had a situation where this trick didn't work after all. That means, that your application's functionality (element autoresizing or too deep view/subview integration or probably something else) is not allowing this feature to work. sorry. In simple cases it helps. – Guntis Treulands Jan 08 '13 at 15:21
  • In viewcontroller, which needs specific rotation. – Guntis Treulands Apr 04 '13 at 08:31
  • It crash my app. I am using this when movie player dissmiss. – Mangesh Jun 02 '13 at 11:49
  • I am not sure whether it works on modal viewcontroller dismissing. Maybe problem is elsewhere? If You are targeting iOS >= 5.0 - try http://stackoverflow.com/a/9827763/894671 – Guntis Treulands Jun 02 '13 at 16:26
  • Non-deprecated methods (ios 7): `[self presentViewController:mVC animated:NO completion:nil];` and `[self dismissViewControllerAnimated:NO completion:nil];` – TJez Nov 05 '13 at 02:01
  • Above code worked for me, but it does not seems to be appropriate. And there is minor change in above code, which i have improved. UIViewController *mVC = [[UIViewController alloc] init]; [self presentViewController:mVC animated:NO completion:nil]; [[mVC presentingViewController] dismissViewControllerAnimated:YES completion:nil]; mVC = nil; – Bulla Nov 21 '13 at 09:42
  • This trick works for forcing the orientation. However, all my views are removed from the view controller and it's showing blank page except for the top navigation bar and bottom tab bar. – PokerIncome.com Jun 01 '14 at 04:56
  • Flashes the screen on iOS8. Is there not a more elegant solution? – Shaun Budhram Sep 25 '14 at 08:44
  • 1
    I have the same problem on iOS8 (flashes). In my situation, I need change device rotation during subview transitions. To reduce this flash effect, I have changed background color of presented view to white. – Aist Marabu Oct 16 '14 at 10:56
  • It actually did not work, all view suddenly disappear and only white page with Back button on top(UINavigationController used) – Yucel Bayram Mar 11 '15 at 07:50
  • In IOS 8.4 it takes some time. so a little bit flickering occur. any solution?? – Mihir Oza Aug 13 '15 at 09:40
  • not working for me when device force rotate in Portrait mode after image capturing in landscape. – Mihir Oza Aug 17 '15 at 12:44
19

This might help. You can call the following method upon appearing, where appropriate. e.g. in -viewWillAppear:animated

attemptRotationToDeviceOrientation Attempts to rotate all windows to the orientation of the device.

+ (void)attemptRotationToDeviceOrientation

Discussion

Some view controllers may want to use app-specific conditions to determine the return value of their implementation of the shouldAutorotateToInterfaceOrientation: method. If your view controller does this, when those conditions change, your app should call this class method. The system immediately attempts to rotate to the new orientation. A rotation occurs so long as each relevant view controller returns YES in its implementation of the shouldAutorotateToInterfaceOrientation: method.

Availability

Available in iOS 5.0 and later. http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIViewController_Class/Reference/Reference.html

Sierra Alpha
  • 3,707
  • 4
  • 23
  • 36
  • 1
    wow +1 good tip (and another goody in os5). this problem has given me many hours of headache. – danh Mar 24 '12 at 05:31
  • 1
    There are all kinds of functions to set the autorotation settings there, but they don't seem to be consistently called. I put -(BOOL) shouldAutorotate { return NO; } But this never got called. – shim Oct 26 '12 at 04:52
  • Awesome - so good! This has eluded me for years! Thanks so much – joehanna Feb 01 '17 at 03:27
4

Use this,

[[UIDevice currentDevice]performSelector:@selector(setOrientation:) withObject:(__bridge id)((void *)UIInterfaceOrientationLandscapeRight)];
Thangavel
  • 216
  • 2
  • 10