15

My root view controller's implementation of supportedInterfaceOrientations almost always returns UIInterfaceOrientationMaskAll, however there is one edge case where it returns UIInterfaceOrientationMaskLandscape.

This is working, if the user rotates the device. However if the device is being held in portrait mode the supportedInterfaceOrientations method does not ever get called, unless the user manually rotates the device.

How can I programatically tell the system that the return value of this method has changed?

According to the documentation, it seems like I should be able to call [UIViewController attemptRotationToDeviceOrientation] however this does not have any effect (supportedInterfaceOrientations is never called and the screen does not rotate).

I found various workarounds others have posted to try and solve this problem, but none of them work in my tests. I suspect they may have worked in iOS 5.0, but not iOS 6.0.

I am returning YES in the root view controller's shouldAutorotate method.

Abhi Beckert
  • 32,787
  • 12
  • 83
  • 110
  • Did you ever resolve this? I recently asked a similar question in iOS7: http://stackoverflow.com/questions/20987249/how-do-i-programmatically-set-device-orientation-in-ios7 – John Stewart Jan 08 '14 at 22:59

3 Answers3

1

First of all, it might be useful if you used this if you want to present your UIViewController in Landscape mode.

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight;
}

Also, A lot depends on with which controller is your UIViewController embedded in.

Eg, If its inside UINavigationController, then you might need to subclass that UINavigationController to override orientation methods like this.

subclassed UINavigationController (the top viewcontroller of the hierarchy will take control of the orientation.) needs to be set it as self.window.rootViewController.

- (BOOL)shouldAutorotate
 {
     return self.topViewController.shouldAutorotate;
 }
 - (NSUInteger)supportedInterfaceOrientations
 {
     return self.topViewController.supportedInterfaceOrientations;
 }

From iOS 6, it is given that UINavigationController won't ask its UIVIewControllers for orientation support. Hence we would need to subclass it.

Note :

The shouldAutorotate and supportedInterfaceOrientations method always get called for UINavigationController whenever Push operations are done.

mayuur
  • 4,736
  • 4
  • 30
  • 65
  • My view hierarchy is complex. The root controller is a tab bar controller, which forwards onto the active tab. The active tab view controller contains a navigation controller (among other things), and all controllers except one that can be pushed to navigation controller work in any orientation. They're all subclassed and returning the correct orientation settings, I have confirmed via breakpoints that when my landscape only view is pushed, it does return `UIInterfaceOrientationMaskLandscape` and that value is returned by the root view controller, but it doesn't rotate; it stays in portrait. – Abhi Beckert Nov 05 '12 at 09:54
  • If the user rotates to landscape, it switches to landscape and won't go back to portrait. But when the view is pushed, even though it returns landscape only, it still stays in portrait until being rotated manually. This particular view is for drawing a signature with your finger, and it really needs to be landscape due to business logic of where the signature gets used (after being uploaded to a remote server). My client is pretty annoyed, since it worked in iOS 5, but now doesn't in iOS 6 despite lots of debugging. >:( – Abhi Beckert Nov 05 '12 at 09:55
  • Did you try subclassing your `UINavigationController`? I had a similar problem earlier, and it got solved by this method. – mayuur Nov 05 '12 at 09:58
  • Actually what happens is, in iOS < 6.0 versions, each and every `UIViewController` had the right to rotate by itself and support Orientations whatever it needed. But, in iOS 6, `UIViewController` has to ask for permission from what its subclassed under, eg. `UINavigationController` or `UITabbarController` – mayuur Nov 05 '12 at 10:02
  • Yes, the nav controller is subclassed, and is returning landscape as it's only supported orientation (when a specific view has been pushed). – Abhi Beckert Nov 05 '12 at 10:44
0

Quote from Apple's UIViewController Class Reference:

Note: At launch time, apps should always set up their interface in a portrait orientation. After the application:didFinishLaunchingWithOptions: method returns, the app uses the view controller rotation mechanism described above to rotate the views to the appropriate orientation prior to showing the window.

http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html

If the interface starts in portrait the autorotation should be able to handle the adjustment even if the user opens the app with the device on its side.

Update: I found this post that should help with rotations after launch. Apparently iOS 6 looks at the navigation controller to determine supported device orientations.

How to force a UIViewController to Portrait orientation in iOS 6

Community
  • 1
  • 1
danielM
  • 2,462
  • 2
  • 20
  • 21
  • I'm not talking about at launch time, I'm talking about when the user taps a button in one of the views, which takes you into an area of the app that cannot be used in portrait. The interface for one view controller can only be used in 16:9 aspect ratio. 9:16 is totally unacceptable. – Abhi Beckert Oct 31 '12 at 03:27
  • I misunderstood your questions. See my updated answer. Hopefully that helps! – danielM Oct 31 '12 at 13:05
  • I have done all of that, it still doesn't work. I have a navigation controller, showing a view controller in portrait mode. You tap a button, and it pushes a new view controller which cannot be used in portrait mode. On iOS 5, it would rotate to landscape. On iOS 6, it says in portrait mode even though the view controllers are all returning "landscape only" in the relevant methods. If the user rotates the phone to landscape, it switches to landscape and cannot be changed back to portrait, so it's working. I want it to switch to landscape when the view is pushed, which is what it did in iOS 5 – Abhi Beckert Nov 03 '12 at 09:05
0

You need to manually rotate it. You'll want to call the following logic in your view controller's viewWillAppear: method:

UIDeviceOrientation curDevOrientation = [[UIDevice currentDevice] orientation];
if (![self supportsOrientation:curDevOrientation]) {
    // We're going to rotate 90 degrees clockwise.  First figure out what that
    // means to the status bar.
    UIInterfaceOrientation newStatusBarOrientation;
    switch (curDevOrientation)  {
        case UIDeviceOrientationPortrait:
            newStatusBarOrientation = UIInterfaceOrientationLandscapeRight;
            break;
        case UIDeviceOrientationPortraitUpsideDown:
            newStatusBarOrientation = UIInterfaceOrientationLandscapeLeft;
            break;
    }
    [[UIApplication sharedApplication] setStatusBarOrientation:newStatusBarOrientation animated:NO];

    // Now rotate the view 90 degrees clockwise.
    CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI * 90.0 / 180.0);
    self.view.transform = transform;
}

That should rotate the particular view controller's view, whenever it appears.

KevinH
  • 2,034
  • 1
  • 12
  • 12