shouldAutorotateToInterfaceOrientation不在iOS 6中调用

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

这一切都在iOS 5上工作正常,但在iOS 6(模拟器和iPad) shouldAutorotateToInterfaceOrientation永远不会被调用。

这是一个错误,我应该期望与iOS 6的最终版本或我不知道已经改变的东西解决?

请仔细阅读这一点,否则你可能会放松你的生命1-2天,疯狂和战斗,摇晃,把你的testing设备,如动物园里的黑猩猩抓住访客的手机! 迟早…诺言:)

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

意识到

UIInterfaceOrientationUIApplication一个属性,只包含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即可。

从iOS 6开始,应用程序启动过程中会检查3个级别和3个步骤,如果需要,您必须控制这3个步骤。

 1. Info.plist - Supported Interface Orientations 

您可以在“摘要”选项卡中以graphics方式设置。 允许的方向序列是重要的,您可以通过编辑info.plist手动更改,并且设备将在应用程序启动时select第一个! 这是至关重要的,因为问题始终是应用程序的启动,当[UIDevice currentDevice].orientation是未知的时候,特别是当我们在平面上testing我们的应用程序时。

XCode中的plist设置(信息)

BE AWARE (iPad)或(iPhone)扩展名有其他两种设置可能性,如果使用其中任何一种设置,则将使用当前设备或模拟器的设置,忽略没有扩展名的常规设置。 所以,如果你只运行一个iPhone应用程序,而且不小心在plist的某个地方留下了一个“支持的界面方向(iPad)”行,那么它将忽略你之前在常规设置中build立的规则(在我的iPhone例子中),即使您的应用程序不打算在iPhone上使用某个给定的方向,但您的应用程序中仍会出现“我们发现您的应用程序不符合在iPad上运行的要求”将使用它可能会导致不可预知的错误,因为所有的iPhone应用程序也必须在提交过程中在iPad上运行。

 2. AppDelegate - application:supportedInterfaceOrientationsForWindow 

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

 3. Top-level view controller or RootViewController - supportedInterfaceOrientations 

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

 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类的类别附件,因为这是最顶层的控制器,如果您还没有创build它的子类别,则没有可以设置的位置/代码它的方向设置,所以你需要强制它检查你的真正的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 

在此之后,你可以在你的“最顶层的” ViewController (在我的例子中这是detailViewController )用你在iOS 6中为ViewControllers提供的任何方法来设置首选的方向,如下所示:

 1. (BOOL)shouldAutorotate 2. (NSUInteger)supportedInterfaceOrientations 3. (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation 

好吧,我得到它在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卡反正)

设置应用程序窗口路线控制器,而不是,只是添加它的视图作为子视图为我工作(如Rocotilos做的)

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

这里是iOS 5和更早的代码的解决scheme,不涉及重复您的逻辑。 只需将此代码添加到您的视图控制器,并从现有的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; } 

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

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

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

尽pipe许多响应都提供了解决scheme – 即实现shouldAutorotate和supportedInterfaceOrientations for iOS 6构build – 您还应该注意,如果您的视图控制器托pipe在导航控制器中,那么它们都不重要,因为运行时将在UINavigationController实例上调用这些实例,否则将忽略您的代码。

显然,“解决scheme”是inheritanceUINavigationController并在这个子类上实现这些新的方法,如下所述: iOS 6 UITabBarController支持使用当前UINavigation控制器的方向

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

这是我见过的iOS版本中最没有意义和最令人讨厌的重大改变之一。

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

这适用于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 } } 

作为对@Rocotilos的回应,我在代码中发现了一个附录,在论坛的其他地方没有看到。 我遇到了应用程序生命周期刚刚开始的情况,在shouldAutorotate方法中,方向未知。 这导致应用程序不能在横向上正确显示视图。 在模拟器中旋转几次后,它工作正常。

我的情况是,有一些意见,我们会想要横向布局popup。 因此,我们不希望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; } 

事实certificate,只有根视图处理这些调用。 在我的情况下,这是一个正常的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]; } } 

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

以下是苹果的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,结帐弗拉基米尔的答案 。

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

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

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

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

 - (NSUInteger)supportedInterfaceOrientations{ if(UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation])) return UIInterfaceOrientationMaskPortrait; else return UIInterfaceOrientationMaskLandscape; } 
 -(BOOL)shouldAutorotate { UIDeviceOrientation orientation = [UIDevice currentDevice].orientation; if (orientation == UIDeviceOrientationUnknown) { return YES; } return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation]; } 

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级别的testing。

如果你想限制支持的方向,你应该在UIApplicationDelegate级别使用

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

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

 -(NSUInteger)supportedInterfaceOrientations 

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

它为我工作:

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

苹果已经弃用从ios6应用程序的方法,而不是使用这些方法。 看到你的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);