ios6 - shouldAutorotateToInterfaceOrientation未在iOS 6中调用




(15)

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

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

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

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


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

-(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-SW19http://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

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


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

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

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


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

它为我工作:

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

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

是的,问题是只调用window.rootViewController方法返回方向掩码。 所以supportedInterfaceOrientations方法必须在viewController中实现,它设置为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;
}

以下是Apple的iOS SDK,XCode4.5 +的引用(参见UIViewController类参考,处理视图旋转):

在iOS 6中,您的应用程序支持应用程序的Info.plist文件中定义的界面方向。 视图控制器可以覆盖supportedInterfaceOrientations方法以限制支持的方向列表。 通常, 系统仅在窗口的根视图控制器或呈现的视图控制器调用此方法以填充整个屏幕 ; 子视图控制器使用由父视图控制器为其提供的窗口部分,不再直接参与有关支持哪些旋转的决策。

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

所以在你的根视图控制器中,你做ff:

- (BOOL)shouldAutorotate {
  return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskPortrait;
}

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

- (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的答案 。


为了回应@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;
}

请仔细阅读,或者你可以放松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;
}

意识到

UIInterfaceOrientationUIApplication一个属性,只包含4种与状态栏方向相对应的可能性:

UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,

UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,

UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,

UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft

不要混淆它

UIDeviceOrientationUIDevice类的一个属性,包含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个步骤,如果您愿意,您必须控制它们。

1. Info.plist - Supported Interface Orientations

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

注意 (iPad)或(iPhone)扩展有两种其他设置可能性,如果您使用其中任何一种,它将使用当前设备或模拟器的设置而忽略没有扩展名的常规设置。 因此,如果您运行仅限iPhone的应用程序,并且不小心您在plist中的某个位置留下了“支持接口方向(iPad)”行,即使没有任何数据,也会忽略您之前在常规设置中建立的规则(在我的iPhone示例中) )你可以拒绝你的应用程序的文字“我们发现你的应用程序不符合在iPad上运行的要求......”即使你的应用程序不打算在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;

在这种情况下,您必须将以下代码作为NavigationController类的类别附件放在AppDelegate中,因为这是最顶层的控制器,如果您还没有创建它的子类别,则您没有可以设置的位置/代码它的方向设置,所以你需要强制它检查你真正的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 for ViewControllers提供的任何方法在“最顶层” ViewController (在我的示例中为detailViewController )中设置首选方向,如下所示:

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中)


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

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

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

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








ios ios6 orientation