shouldAutorotateToInterfaceOrientation未在iOS 6中调用

时间:2012-09-04 09:14:29

标签: ios ios6 orientation

我正在使用MGSplitViewController,而我正在使用shouldAutorotateToInterfaceOrientation来控制旋转时主视图控制器的大小。

它在iOS 5上运行良好,但在iOS 6(模拟器和iPad)上shouldAutorotateToInterfaceOrientation永远不会被调用。

这是一个我应该期望在iOS 6的最终版本中修复的错误,或者我不知道的东西已经改变了吗?

17 个答案:

答案 0 :(得分:128)

请仔细阅读这篇文章,否则你可能会因为坚果和战斗,摇晃,转动你的测试设备就像动物园里的黑猩猩那样抓住了一个访客的手机!迟早......承诺:)

在iOS 6中

shouldAutorotateToInterfaceOrientation:

已弃用,已替换为

shouldAutorotate

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

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

之前 iOS6(iOS5,iOS4等)

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

}

return YES;
}

你应该使用

AFTER iOS 6 +

- (BOOL)shouldAutorotate {

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

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

}

return YES;
}

BE AWARE

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]; 返回UIDeviceOrientation - 设备的实际方向 - 但你必须知道 UIDeviceOrientation 并不总是等于 UIInterfaceOrientation !!!例如,当您的设备位于普通桌面上时,您可能会收到意外的值。

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

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

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

1. Info.plist - Supported Interface Orientations

您可以在摘要标签中以图形方式设置。允许的方向序列是重要的,您可以通过编辑info.plist手动更改,设备将在应用程序启动时选择第一个!这是至关重要的,因为在[UIDevice currentDevice].orientation未知的情况下,尤其是当我们在平面上测试我们的应用程序时,问题始终是应用程序的启动。

plist setting in XCode (Info)

BE AWARE (iPad)或(iPhone)扩展有两种其他设置可能,如果您使用其中任何一种,它将使用当前设备或模拟器的设置,而忽略没有扩展名的常规设置。因此,如果您运行仅限iPhone的应用程序,并且意外地您离开了支持界面方向(iPad)&#34;在没有任何数据的情况下在plist的某个地方划线,它会忽略你之前在常规设置中建立的规则(在我的iPhone示例中),你可以通过文本拒绝你的应用程序&#34;我们发现你的应用程序不符合在iPad上运行的要求......&#34;即使您的应用程序并不打算在iPhone上使用给定的方向,但iPad会使用它可能会导致不可预测的错误,因为所有iPhone应用程序也必须在提交过程中在iPad上运行。

2. AppDelegate - application:supportedInterfaceOrientationsForWindow

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

3. Top-level view controller or RootViewController - supportedInterfaceOrientations

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

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

在此之后,您可以在&#34; topmost&#34;中设置首选方向。 ViewController(在我的示例中为detailViewController),其中包含iOS 6中ViewControllers提供的任何方法,如下所示:

1. (BOOL)shouldAutorotate

2. (NSUInteger)supportedInterfaceOrientations

3. (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation

答案 1 :(得分:55)

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

我只是在你之前和之后告诉你,它应该是自我解释的:

<强> BEFORE

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

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

}

return YES;
}

<强> AFTER

- (BOOL)shouldAutorotate {

UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];

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

}

return YES;
}

对于支持的方向,您可以在info.plist中指定: Supported Orientation pic

或使用代码:

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

编辑:第二个想法,如果您打算支持较低版本(iOS4.3 / 5 / 5.1)以及6.0,那么只需包含具有相同代码内容的两种方法。对我有用(无论如何都是sim)

答案 2 :(得分:20)

设置应用程序窗口路径控制器而不是仅仅添加它作为子视图的视图对我有效(如Rocotilos所做的那样)

//    [self.window addSubview:self.topLevelNavigationController.view];
self.window.rootViewController = self.topLevelNavigationController;

答案 3 :(得分: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;
}

答案 4 :(得分:15)

我的快速解决方法是在我的根视图控制器上添加此代码

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

这样我仍然使用与iOS 6之前的版本相同的逻辑。当然,我最初在我的应用程序中设置了我的rootViewController委托,并且只是添加到windows子视图中的didFinishLaunchingWithOptions。

答案 5 :(得分:11)

虽然许多响应都指出了解决方案 - 要实现iOS6构建的shouldAutorotate和supportedInterfaceOrientations,但您还应该知道,如果您的视图控制器托管在导航控制器中,那么它们都不会因为运行时将在UINavigationController实例上调用它们,否则忽略您的代码。

显然'解决方案'是子类UINavigationController并在这个子类上实现这些新方法,如下所述: iOS 6 UITabBarController supported orientation with current UINavigation controller

然后您可以更改所有使用UINavigationController的代码来代替使用这个新的子类。

这必须是我见过的iOS版本中最无意义和最烦人的突破性变化之一。

答案 6 :(得分: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;
}

答案 7 :(得分: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;
}
ViewController上的

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

{
    if (UIInterfaceOrientationIsLandscape(interfaceOrientation))

    {
      // landscape
    }
    else
    {
      //portrait
    }
}

答案 8 :(得分:3)

在回应@Rocotilos时,我的代码中出现了一个附录,我在论坛的其他地方没见过。我遇到了应用程序生命周期的最初阶段,在shouldAutorotate方法中未知方向。这导致应用程序无法在横向中正确显示视图。在模拟器中经过几次旋转后,它工作正常。

我的情况是,某些视图会出现在我们想要横向布局的地方。因此,我们不希望shouldAutorotate返回YES。我意识到这对某些人来说可能是一种罕见的情况,但我已经花了很多时间来诊断这一点并希望传递。希望这有用。

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

答案 9 :(得分: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的应用程序中执行此操作: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

答案 10 :(得分: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];
        }
}

答案 11 :(得分:2)

是的,问题是只调用window.rootViewController方法返回方向掩码。 因此必须在viewController中实现 supportedInterfaceOrientations 方法,该方法设置为window.rootViewController。但在大多数情况下,此对象不是自定义类,例如UINavigationController的。一种可能的解决方案是子类UINavigationController。但Apple说:“这个类不是用于子类化的”,所以我宁愿使用另一个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;
}

答案 12 :(得分: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);

答案 13 :(得分: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;
}

答案 14 :(得分: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

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

-(NSUInteger)supportedInterfaceOrientations

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

答案 15 :(得分:1)

-(BOOL)shouldAutorotate
{
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;

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

    return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation];
}

答案 16 :(得分: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;