9
votes

According to the UIViewController docs here,

https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/clm/UIViewController/attemptRotationToDeviceOrientation

using [UIViewController attemptRotationToDeviceOrientation] forces the system to attempt to rotate the interface to a new orientation. I am attempting to force an interface rotation from portrait to landscape by:

  • setting a forceLandscape flag before attempting the rotation
  • Calling [UIViewController attemptRotationToDeviceOrientation]
  • implementing -supportedInterfaceOrientations in my view controller and checking a flag to change the supported orientations, e.g.

This forces -supportedInterfaceOrientations to be called again, which looks like

- (NSUInteger)supportedInterfaceOrientations {
    return self.forceLandscape ? UIInterfaceOrientationMaskLandscapeLeft : UIInterfaceOrientationMaskPortrait;
}

Even though -supportedInterfaceOrientations is being called and returns the new orientation, the interface does not rotate. I have confirmed that the project allows all orientations and that this view controller is the window's root view controller. Has anyone else run into this problem and found a solution? I am aware of all the hacks to fix this (presenting and dismissing modals, etc), but I would like a clean solution if possible. I have verified this issue on iOS 6 and 7.

Below is the complete code to reproduce:

@interface ALTViewController ()
@property (nonatomic, assign) BOOL forceLandscape;
@end

@implementation ALTViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {

        self.forceLandscape = NO;
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    [button setTitle:@"button" forState:UIControlStateNormal];
    [button sizeToFit];
    [self.view addSubview:button];
    button.center = self.view.center;
    [button addTarget:self
               action:@selector(buttonPressed:)
     forControlEvents:UIControlEventTouchUpInside];
}

- (void)buttonPressed:(id)sender
{
    self.forceLandscape = YES;
    [UIViewController attemptRotationToDeviceOrientation];
}

- (NSUInteger)supportedInterfaceOrientations
{
    return self.forceLandscape ? UIInterfaceOrientationMaskLandscapeLeft : UIInterfaceOrientationMaskPortrait;
}
2
Within your question, you seem to mix the term device with the term interface which makes it a bit hard to understand what you are attempting to achieve. Are you attempting to rotate the interface to new orientation even though the device remains in the same orientation?Till
Till - agreed :) I just edited the question for clarity. You are right, I am trying to force the interface from portrait to landscape orientation while the device remains in portrait orientation.alexshafran

2 Answers

11
votes

A call to attemptRotationToDeviceOrientation only rotates the orientation of the interface, if and only if, the device itself has been rotated.

If your view controller only supported portrait orientation, for example, and the user rotated the device to landscape orientation, no interface rotation would occur. While the device was in landscape orientation, let's say your code toggles a flag which allows for landscape orientation. What would happen to the interface orientation? Nothing, because device orientation has already occurred. To get the interface orientation to match the device orientation, you would need to call attemptRotationToDeviceOrientation.

In my own code, I recently created a custom, multi-part view animation that didn't look right if interface rotation occurred in the middle of it. So I turned off interface rotation during the brief animation. If the user rotated the device during the animation, no interface orientation would occur. However, when interface orientation was turned back on, the interface would not rotate to match the device orientation until I called attemptRotationToDeviceOrientation.