9

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;
}
4

2 回答 2

11

当且仅当设备本身已旋转时,对 attemptRotationToDeviceOrientation 的调用仅旋转界面的方向。

例如,如果您的视图控制器仅支持纵向,而用户将设备旋转为横向,则不会发生界面旋转。当设备处于横向时,假设您的代码切换了一个允许横向的标志。界面方向会发生什么?什么都没有,因为设备方向已经发生。要使界面方向与设备方向相匹配,您需要调用尝试RotationToDeviceOrientation。

在我自己的代码中,我最近创建了一个自定义的多部分视图动画,如果中间发生界面旋转,它看起来不正确。所以我在简短的动画中关闭了界面旋转。如果用户在动画期间旋转设备,则不会出现界面方向。但是,当重新打开界面方向时,界面不会旋转以匹配设备方向,直到我调用了尝试旋转到设备方向。

于 2013-10-01T20:39:36.423 回答
2

您可以尝试通过以下方式实现某些目标: setStatusBarOrientation:animated: https://developer.apple.com/library/ios/documentation/uikit/reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/instm/UIApplication/ setStatusBarOrientation:动画

这为我解决了类似的问题。

于 2013-10-02T08:27:34.073 回答