65

I'm using MGSplitViewController and I'm usingshouldAutorotateToInterfaceOrientation to control the size of the master view controller on rotation.

It's all working fine on iOS 5 but on iOS 6 (both simulator and iPad) shouldAutorotateToInterfaceOrientation is never called.

Is this a bug that I should expect to be fixed with the final release of iOS 6 or something that I'm not aware of has changed?

4

17 回答 17

132

请仔细阅读此内容,否则您可能会因为发疯、打架、摇晃、转动您的测试设备而失去 1-2 天的生命,就像动物园里的黑猩猩抓住游客的手机一样!迟早......承诺:)

在 iOS 6 中

shouldAutorotateToInterfaceOrientation:

已弃用并替换为

shouldAutorotate

这意味着 iOS 6 永远不会调用shouldAutorotateToInterfaceOrientation

因此,如果您在应用程序中使用了以下内容

iOS6 之前(iOS5、iOS4 等)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait) {
// your code for portrait mode

}

return YES;
}

你应该使用

iOS 6+之后

- (BOOL)shouldAutorotate {

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

if (orientation == UIInterfaceOrientationPortrait) {
// your code for portrait mode

}

return YES;
}

意识到

UIInterfaceOrientation是一个属性,UIApplication并且仅包含 4 种与状态栏方向相对应的可能性:

UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,

UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,

UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,

UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft

不要将其与

UIDeviceOrientation这是UIDevice类的一个属性,包含 7 个可能的值:

UIDeviceOrientationUnknown - Can not be determined

UIDeviceOrientationPortrait - Home button facing down

UIDeviceOrientationPortraitUpsideDown - Home button facing up

UIDeviceOrientationLandscapeLeft - Home button facing right

UIDeviceOrientationLandscapeRight - Home button facing left

UIDeviceOrientationFaceUp - Device is flat, with screen facing up

UIDeviceOrientationFaceDown - Device is flat, with screen facing down

即使你理论上可以使用UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];which 返回UIDeviceOrientation- 设备实际方向 - 但你必须知道这UIDeviceOrientation并不总是相等的UIInterfaceOrientation!例如,当您的设备放在普通桌子上时,您可能会收到意想不到的价值。

您也可以使用UIInterfaceOrientation orientation = self.interfaceOrientation;which 返回UIInterfaceOrientation界面的当前方向,但它是 的属性UIViewController,因此您只能在UIViewController类中访问它。

如果您想同时支持之前的 iOS6 (iOS3/4/5) 和 iOS6 设备 - 这可能很明显 - 只需在您的代码中同时使用shouldAutorotateToInterfaceOrientation:和。shouldAutorotate

从 iOS 6开始,设备在应用启动期间会检查 3 个级别和 3 个步骤,如果您愿意,您必须对其进行控制。

1. Info.plist - Supported Interface Orientations

您可以在“摘要”选项卡中以图形方式设置。允许的方向顺序很重要,您可以通过编辑 手动更改它info.plist,并且设备将在应用程序启动时选择第一个!这一点至关重要,因为当有可能[UIDevice currentDevice].orientation未知时,应用程序的启动总是会出现问题,尤其是当我们在平坦的表面上测试我们的应用程序时。

XCode 中的 plist 设置(信息)

请注意 (iPad) 或 (iPhone) 扩展程序还有其他两种设置可能性,如果您使用其中任何一种,它将使用当前设备或模拟器的设置,而忽略没有扩展程序的常规设置。因此,如果您运行仅 iPhone 的应用程序并且不小心在 plist 中的某处留下了“支持的界面方向 (iPad)”行,即使没有任何数据,它也会忽略您之前在常规设置中建立的规则(在我的 iPhone 示例中) ) 并且即使您的应用不打算在 iPhone 上使用给定的方向,但 iPad将使用它,这可能会导致无法预料的错误,

2. AppDelegate - application:supportedInterfaceOrientationsForWindow

返回您希望允许的每个方向的位掩码列表,它会覆盖 info.plist 设置。每次设备旋转时至少调用一次。

3. Top-level view controller or RootViewController - supportedInterfaceOrientations

它与应用程序和应用程序委托的集合产生交集,该集合必须具有非零结果以避免崩溃。每次设备旋转时至少调用一次,除非我们的控制器中安装了另一种方法:

shouldAutorotate

这会干扰应用程序允许的方向,并给出BOOL默认值YES

BE CAREFUL when you use `NavigationController`

作为您的最顶层控制器AppDelegate,如下所示:

DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
UINavigationController *navigationController=[[UINavigationController alloc] initWithRootViewController:detailViewController];
self.window.rootViewController =nil;
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;

在这种情况下,您必须将以下代码AppDelegate作为类的类别附件放置在您的NavigationController类中,因为这是最顶层的控制器,如果您没有对其子类别,则没有可以设置其方向的位置/代码设置,因此rootViewController在这种情况下,您需要强制它检查您的真实情况detailViewController

@implementation UINavigationController (OrientationSettings_IOS6)

-(BOOL)shouldAutorotate {
return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations {
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end

在此之后,您可以使用 iOS 6 中可用的任何方法在“最顶部” ViewController(在我的示例中为)中设置首选方向,如下所示:detailViewControllerViewControllers

1. (BOOL)shouldAutorotate

2. (NSUInteger)supportedInterfaceOrientations

3. (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
于 2013-02-18T14:20:04.193 回答
55

好的,我让它在 iOS6 iPad 模拟器中工作。耶。这是我所做的:

我只是给你看之前和之后,它应该是不言自明的:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

if (interfaceOrientation==UIInterfaceOrientationPortrait) {
 // do some sh!t

}

return YES;
}

- (BOOL)shouldAutorotate {

UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];

if (orientation==UIInterfaceOrientationPortrait) {
 // do some sh!t

}

return YES;
}

至于支持的方向,您可以在 info.plist 中指定如下: 支持的方向图片

或使用代码:

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait; // etc
}

编辑:再想一想,如果您计划支持较低版本(iOS4.3/5/5.1)以及 6.0,那么只需包含具有相同代码内容的两种方法。为我工作(无论如何在 sim 中)

于 2012-09-17T08:20:15.663 回答
20

设置应用程序窗口路由控制器,而不是仅将其视图添加为对我有用的子视图(就像 Rocotilos 所做的那样)

//    [self.window addSubview:self.topLevelNavigationController.view];
self.window.rootViewController = self.topLevelNavigationController;
于 2012-09-21T09:35:14.950 回答
18

这是 iOS 5 和更早版本代码的解决方案,不涉及复制您的逻辑。只需将此代码添加到您的视图控制器,它就会从您现有的 shouldAutorotateToInterfaceOrientation 方法生成supportedInterfaceOrientations。

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations{
NSInteger mask = 0;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeRight])
    mask |= UIInterfaceOrientationMaskLandscapeRight;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeLeft])
    mask |= UIInterfaceOrientationMaskLandscapeLeft;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortrait])
    mask |= UIInterfaceOrientationMaskPortrait;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortraitUpsideDown])
    mask |= UIInterfaceOrientationMaskPortraitUpsideDown;
return mask;
}
于 2012-10-16T20:05:00.790 回答
16

对我来说一个快速的解决方法是在我的根视图控制器上添加这个代码

- (BOOL)shouldAutorotate {
    return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation];
}

这样,我仍然使用与 iOS 6 之前的版本相同的逻辑。当然,我最初在我的应用程序委托中正确设置了 rootViewController,而不是仅仅添加到 Windows 子视图中。

于 2012-09-25T09:39:00.030 回答
11

虽然许多响应都指出了解决方案——即为 iOS 6 构建实现 shouldAutorotate 和 supportedInterfaceOrientations——但您还应该意识到,如果您的视图控制器托管在导航控制器中,那么这一切都无关紧要,因为运行时将在 UINavigationController 实例上调用这些,否则忽略您的代码。

显然,“解决方案”是将 UINavigationController 子类化并在此子类上实现这些新方法,如下所述: iOS 6 UITabBarController support orientation with current UINavigation controller

然后你有幸改变你使用 UINavigationController 的所有代码来使用这个新的子类。

这一定是我见过的 iOS 版本中最无意义和最烦人的重大更改之一。

于 2012-10-11T02:04:02.153 回答
10

IOS 5

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
if (UIInterfaceOrientationLandscapeLeft) {
        return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
    }
    if (UIInterfaceOrientationLandscapeRight) {
        return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
    }
    return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

IOS 6

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations:(UIWindow *)window{

    //    UIInterfaceOrientationMaskLandscape;
    //    24
    //
    //    UIInterfaceOrientationMaskLandscapeLeft;
    //    16
    //
    //    UIInterfaceOrientationMaskLandscapeRight;
    //    8
    //
    //    UIInterfaceOrientationMaskPortrait;
    //    2


    //    return UIInterfaceOrientationMaskLandscape;
    return 24;
}
于 2012-10-10T06:55:21.007 回答
3

这适用于 iOS6 和 Xcode 4.5 GM:

在 AppDelegate.m 上

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    .....

    //   self.window.rootViewController = self.navigationController;

    [window setRootViewController:navigationController];

    .....

    return YES;
}

在视图控制器上:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration

{
    if (UIInterfaceOrientationIsLandscape(interfaceOrientation))

    {
      // landscape
    }
    else
    {
      //portrait
    }
}
于 2012-09-14T03:33:26.927 回答
3

这是来自 Apple 的 iOS SDK XCode4.5+ 的引用(请参阅 UIViewController 类参考,处理视图旋转):

在 iOS 6 中,您的应用支持在应用的 Info.plist 文件中定义的界面方向。视图控制器可以覆盖supportedInterfaceOrientations方法来限制支持的方向列表。一般情况下,系统只会在窗口的根视图控制器或呈现为填满整个屏幕的视图控制器上调用此方法;子视图控制器使用其父视图控制器为它们提供的窗口部分,并且不再直接参与有关支持哪些旋转的决策。

同样在 iOS6 中, UIViewController 类的 shouldAutorotateToInterfaceOrientation :方法已被弃用。

因此,在您的根视图控制器中,您执行 ff:

- (BOOL)shouldAutorotate {
  return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskPortrait;
}

顺便说一句,“根视图控制器”是您设置为appDelegate窗口对象的 rootViewController的任何 UIViewController 子类。您通常在 appDelegate 的application:didFinishLaunchingWithOptions:方法中执行此操作。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  // Override point for customization after application launch.
  self.window.rootViewController = [FFDashboardController create];
  [self.window makeKeyAndVisible];
  return YES;
}

至于使用 UINavigationController 作为根 VC,请查看Vladimir's answer

于 2012-11-15T14:04:08.507 回答
3

In response to @Rocotilos, I've got an addendum that occurred in my code that I've not seen elsewhere in the forums. I ran into a situation where at the very beginning of the app's life cycle, where the orientation was not known in the shouldAutorotate method. This was causing the app to not display the view properly in landscape. After a few rotations in the simulator it was working fine.

My scenario is that there are certain views that get popped on where we would want landscape layout. As such, we would not want shouldAutorotate to return YES. I realize this might be a rare case for some, but I've spent plenty of time diagnosing this and wanted to pass along. Hope this is helpful.

- (BOOL) shouldAutorotate {

    BOOL shouldRotate = NO;
    UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];

    if ([self IsCaseWhereWeDontWantLandscapeAutorotation]) {
        shouldRotate = NO;
    } else if (orientation == UIDeviceOrientationUnknown) {
        //Handle the case where the device's orientation is not yet known
        shouldRotate = YES;
    } else {
        //Handle the normal case
        shouldRotate = (orientation == UIInterfaceOrientationMaskLandscape);
    }

    return shouldRotate;
}
于 2012-11-26T02:00:38.627 回答
2

事实证明,只有根视图处理这些调用。在我的例子中,这是一个普通的 UINavigationController。我必须将其更改为添加方法的子类文件。

就我而言,我只想要根视图肖像,其余的肖像+风景。

Appdelegate.h

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    S2MBookAppRootViewController *masterViewController = [[[S2MBookAppRootViewController alloc] initWithNibName:pref.rootNibName bundle:nil] autorelease];
    self.navigationController = [[[S2MBookAppNavController alloc] initWithRootViewController:masterViewController] autorelease];

    self.window.rootViewController = self.navigationController;


    [self.window makeKeyAndVisible];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:YES];

    return YES;
}

和 S2MBookAppNavController(UINavigationController 的子类)

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    if([self.viewControllers count] == 1) return UIInterfaceOrientationMaskPortrait;
    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape;
}

更新:当你想强制方向时(在导航控制器上推送新视图时)试试这个。

使您的 UINavigationController 也成为它自己的委托:

@interface S2MBookAppNavController : UINavigationController <UINavigationControllerDelegate>

@end

在 .m 文件中

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.delegate = self;
    // Do any additional setup after loading the view.
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
        if ([UIViewController respondsToSelector:@selector(attemptRotationToDeviceOrientation)]) {
            //present/dismiss viewcontroller in order to activate rotating.
            UIViewController *mVC = [[[UIViewController alloc] init] autorelease];
            [self presentModalViewController:mVC animated:NO];
            [self dismissModalViewControllerAnimated:NO];
        }
}
于 2012-10-23T15:01:56.297 回答
2

是的,问题只是调用了 window.rootViewController 方法来返回方向掩码。所以supportedInterfaceOrientations方法必须在viewController中实现,设置为window.rootViewController。但在大多数情况下,该对象不是自定义类,例如 UINavigationController。一种可能的解决方案是继承 UINavigationController。但苹果说:“这个类不适合子类化”,所以我宁愿使用另一个 UIViewController 来处理方向并将 UINavigationController 添加为子类。

MyRootViewController * myRoot = [MyRootViewController new];
self.window.rootViewController = myRoot;
[myRoot addChildViewController:navigationController];
[myRoot.view addSubview:navigationController.view];

并在 MyRootViewController 中实现方法:

- (BOOL)shouldAutorotate {
 return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    // return your mask here e.g.:
    return UIInterfaceOrientationMaskPortrait;
}
于 2012-10-30T11:25:55.443 回答
1

我在 UINavigationController 中有一系列视图控制器,其中一个只能是横向的。我通过继承 UINavigationController 并添加以下代码来修复它:

- (NSUInteger)supportedInterfaceOrientations{
   return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

这确保了最顶层的视图控制器指示方向。

但是有一个问题:如果您从仅限于横向的 vc 转移到支持任何方向的 vc,则无论手机的方向如何,新视图都将以横向显示。为了解决这个问题,我将以下代码放入无限制的 viewControllers 中:

- (NSUInteger)supportedInterfaceOrientations{
   if(UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]))       
      return UIInterfaceOrientationMaskPortrait;
   else
      return UIInterfaceOrientationMaskLandscape;
}
于 2013-01-23T12:45:44.867 回答
1

此处标题 UIKit 下的注释:http: //developer.apple.com/library/ios/#releasenotes/General/RN-iOSSDK-6_0/_index.html%23//apple_ref/doc/uid/TP40012166-CH1- SW19为答案提供了一些线索,但并不是全部。我还没有全貌,但这是我迄今为止发现的 iOS 6.0 RTM 的内容。

如果您并没有真正限制支持的方向,而是因为用户旋转了设备而想要做一些事情,那么您可以将逻辑移入

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

- (void)viewWillLayoutSubviews

反而。

这可能是直接替换,但我还没有在低级 iOS 版本中进行测试。

如果你想限制支持的方向,你应该在UIApplicationDelegate水平上做到这一点

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window

该文档指出“系统通过将应用程序supportedInterfaceOrientationsForWindow:方法返回的值与最顶部全屏控制器的supportedInterfaceOrientations 方法返回的值相交来确定是否支持方向。” 但在实验中我发现系统忽略了我支持的视图控制器

-(NSUInteger)supportedInterfaceOrientations

返回值,即使方法被调用。

于 2012-10-03T05:37:09.287 回答
1
-(BOOL)shouldAutorotate
{
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;

    if (orientation == UIDeviceOrientationUnknown) {
        return YES;
    }

    return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation];
}
于 2013-05-10T05:49:59.587 回答
1

Apple 已弃用 ios6 中的 shouldautorate 方法,改为使用这些方法。查看您的 xcode 文档

- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0);
- (NSUInteger)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0);
// Returns interface orientation masks.
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0);
于 2012-11-13T13:30:15.540 回答
0

它为我工作:

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    NSUInteger orientations = UIInterfaceOrientationMaskPortrait;
    if ([self isKindOfClass:[YourViewController class]]) { // Your view class
        orientations |= UIInterfaceOrientationMaskPortraitUpsideDown;
    }
    return orientations;
}

方向:

orientations |= UIInterfaceOrientationMaskLandscapeLeft;
orientations |= UIInterfaceOrientationMaskLandscapeRight;
于 2013-03-08T10:35:01.677 回答