iOS6:supportedInterfaceOrientations不起作用(被调用但界面仍然旋转)

50
在我的应用中,我有多个视图,一些视图需要支持纵向和横向的旋转,而其他视图仅需要支持纵向。因此,在项目摘要中,我已选择了所有方向。

以下代码在iOS 6之前的给定视图控制器上禁用横向模式:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

由于 shouldAutorotateToInterfaceOrientation 在 iOS6 中已经被废弃,因此我已经用以下方法替换:

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMask.Portrait;
}

我可以设置断点以确保此方法在视图出现时被正确调用,但界面仍会旋转为横屏模式,而不考虑我仅返回纵向模式的掩码。 我做错了什么?

目前似乎无法构建具有每个视图不同方向要求的应用程序。它似乎只遵循项目摘要中指定的方向。


请参考此链接可能有所帮助:https://dev59.com/EWcs5IYBdhLWcg3w3HkG#12538622 - Ashvin
这里我发布了关于选项卡控制器旋转的解决方案/经验:https://dev59.com/qWcs5IYBdhLWcg3w0HOz#12774037 - Denis Kutlubaev
我遇到了同样的问题。以下答案非常有帮助:http://stackoverflow.com/questions/12996293/io6-doesnt-call-boolshouldautorotate/12996924#12996924 - Jason Wu
15个回答

71

如果你正在使用 UINavigationController 作为根视图控制器,那么它的 shouldAutorotatesupportedInterfaceOrientations 方法会被调用。

同样的,如果你在使用 UITabBarController 或其他视图控制器,也是一样的。

因此,你需要继承你的导航栏或选项卡控制器并重写它的 shouldAutorotatesupportedInterfaceOrientations 方法。


5
好的,但是这样做会使所有推送的视图都遵循相同的旋转规则,对吗?我想让一些视图旋转,而另一些则不旋转。 - aneuryzm
顺便说一句,我已经子类化了UIVIewController,这样的方法从未被调用过。(只有推送视图的方法才被调用)。 - aneuryzm
1
你应该对主导航控制器(或选项卡控制器)进行子类化。对于你的第一个评论,我会在navController的“supportedInterfaceOrientations”方法中测试哪个控制器可见,并返回正确的支持方向。 - Martin
我会尝试这个,如果它也解决了我的问题,我会点赞 :) 感谢您的见解。 - The Lazy Coder
这不是唯一的原因。这只是supportedInterfaceOrientations可能不被调用的一个原因。尽管如此,这是我第一次看到一个被接受的答案是-1 :) - Martin
子类化导航控制器:https://dev59.com/8WnWa4cB1Zd3GeqP3r-a - vnchopra

30

就是这样!我实际上正在使用[window addSubview:tabBarController.view]; - Ken Pletzer
谢谢!这对我也起作用了。我也有[_window addSubview:self.view]。将其更改为[_window setRootViewController:self]就解决了问题。 - Joris Weimar
@Patrick 看看我的回答,你也许可以做类似的事情(查询导航栈而不是子视图控制器)。 - borrrden
这个解决方案在iOS6中被解释为无法工作,可以在此评论中找到:https://dev59.com/cWct5IYBdhLWcg3wNq0g#iqOeEYcBWogLw_1bFBOm - Xander Dunn
对我来说有效,我的根视图控制器是一个tabBarController:[window setRootViewController:tabBarController]; - Richard Lovejoy
显示剩余3条评论

20

在我的情况下,我有一个UINavigationController和它里面的视图控制器。我不得不子类化UINavigationController,并添加以下方法以支持仅竖屏模式:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}

因此,在UINavigationController子类中,我需要检查当前topViewController支持哪个方向。

- (NSUInteger)supportedInterfaceOrientations
{
    return [[self topViewController] supportedInterfaceOrientations];
}

1
太棒了!topViewController这个东西正是我所缺少的关键。非常感谢! - Henning Schulz
@Pavel,[self topViewController]是什么?这是你创建的方法吗?谢谢! - Alex G
No.topViewController 是 UINavigationController 中的一个属性。 - Pavel
谢谢您!这正是我试图做的:将支持的方向设置为当前在UINavigationController中显示的UIViewController。我的唯一问题是,Apple对UINavigationController的参考文献说:“此类不适用于子类化”。但是,我不确定如何在不子类化UINavigationController的情况下完成此操作。 - Xander Dunn

15

我发现的一件事是,如果你有一个仍在运行的旧应用程序

[window addSubView:viewcontroller.view];  //This is bad in so may ways but I see it all the time...
您需要将其更新为:

您需要将其更新为:

[window setRootViewController:viewcontroller]; //since iOS 4

一旦你这样做了,方向就应该重新开始工作了。


1
这是我希望能点赞两次的另一个答案。你经常看到“不好”的方式,是因为那是Xcode文件>新建项目在过去创建它的方式。 - BP.

14

对于iOS6的最佳方法可在Ray Wenderlich团队的“iOS6 By Tutorials”中找到-http://www.raywenderlich.com/,并且对于大多数情况而言,这种方法要比子类化UINavigationController更好。

我正在使用具有UINavigationController的故事板作为初始视图控制器的iOS6。

//AppDelegate.m-很遗憾,此方法在iOS6之前是不可用的。

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;

if(self.window.rootViewController){
    UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
    orientations = [presentedViewController supportedInterfaceOrientations];
}

return orientations;
}

//MyViewController.m - 返回每个 UIViewController 支持的方向

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}

10

正如其他人所说,如果你正在使用UINavigationController并且想要自定义各种视图,那么你需要子类化UINavigationController并确保拥有以下两个组件:

@implementation CustomNavigationController

// -------------------------------------------------------------------------------
//  supportedInterfaceOrientations:
//  Overridden to return the supportedInterfaceOrientations of the view controller
//  at the top of the navigation stack.
//  By default, UIViewController (and thus, UINavigationController) always returns
//  UIInterfaceOrientationMaskAllButUpsideDown when the app is run on an iPhone.
// -------------------------------------------------------------------------------
- (NSUInteger)supportedInterfaceOrientations
{
    return [self.topViewController supportedInterfaceOrientations]; 
}

// -------------------------------------------------------------------------------
//  shouldAutorotate
//  Overridden to return the shouldAutorotate value of the view controller
//  at the top of the navigation stack.
//  By default, UIViewController (and thus, UINavigationController) always returns
//  YES when the app is run on an iPhone.
// -------------------------------------------------------------------------------
- (BOOL)shouldAutorotate
{
    return [self.topViewController shouldAutorotate];
}

然后在任何仅为纵向视图的界面中,您都需要包括:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

在任何一个视角下,都不会是颠倒的。

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

2
基本上就像上面有人说的那样,但是更详细一些:
  1. Create a new file that is a subclass of UINavigationController
  2. Go to your storyboard and then click on the Navigation Controller, set its class to the one that you just created
  3. In this class(.m file) add the following code so it will remain in portrait mode:

    (BOOL)shouldAutorotate
    {
      return NO;
    } 
    
    (NSUInteger)supportedInterfaceOrientations
    {
     return UIInterfaceOrientationMaskPortrait;
    }
    
这对我有用。

1
我认为最好的方法是创建一个类别(Category),而不是对UINavigationControllerUITabbarController进行子类化。
你的UINavigationController+Rotation.h
#import <UIKit/UIKit.h>

@interface UINavigationController (Rotation)

@end

你的UINavigationController+Rotation.m文件

#import "UINavigationController+Rotation.h"

@implementation UINavigationController (Rotation)

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

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

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


@end

尝试让所有的控制器都导入这个类别,这样就可以完美运行。你甚至可以创建一个不旋转但推动另一个控制器旋转的控制器。


6
在一个分类中覆盖方法是一个非常糟糕的做法,因为你无法保证哪个方法(原始类方法或分类方法)会被调用。 - Shawn Craver

1
这段代码对我起作用了:
-(BOOL)shouldAutorotate {
     return YES;
}

-(NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAll;
}

iPhone/iPad应用程序方向查看我的答案


我实际上正在尝试将方向限制为纵向。我认为你的代码允许所有方向。 - aneuryzm
在您的 info.plist 文件中定义方向限制。我使用此代码用于通用应用程序,iPhone 支持纵向和倒置纵向,而 iPad 支持所有布局。 - tcd

0

如果您正在使用UINavigationController,则必须在UINavigationController的子类中实现shouldAutorotatesupportedInterfaceOrientations

这两个方法可以通过两个步骤来控制,如果shouldAutorotate返回YES,则有效的是supportedInterfaceOrientations。这是一个非常好的组合。

例如,在我的大多数视图中,都是纵向的,除了CoverFlowView和PreviewView。当CoverFlowView转移到PreviewView时,PreviewView希望跟随CoverFlowCView的旋转。

@implementation MyNavigationController

-(BOOL)shouldAutorotate
{

if ([[self.viewControllers lastObject] isKindOfClass:NSClassFromString(@"PreviewView")])

return NO;

else

return YES;

}



-(NSUInteger)supportedInterfaceOrientations

{

if ([[self.viewControllers lastObject] isKindOfClass:NSClassFromString(@"CoverFlowView")])

return UIInterfaceOrientationMaskAllButUpsideDown;

else

return UIInterfaceOrientationMaskPortrait;

}

...

@end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接