31

这个问题是关于 iOS 设备旋转和 UINavigationController 中的多个受控视图。有些视图应该被限制为纵向,有些应该可以自由地自动旋转。如果您尝试使用三个视图创建最简单的设置,您会注意到自动旋转行为有一些非常讨厌的怪癖。然而,这个场景非常简单,所以我认为我要么没有正确地执行自动旋转,要么我忘记了一些东西。

我有一个非常基本的演示应用程序,它展示了它的奇怪之处,我制作了一个视频来展示它的实际效果。

设置非常基本:三个视图控制器称为FirstViewControllerSecondViewController并且ThirdViewController都扩展了一个AbstractViewController显示带有类名称的标签,并且shouldAutorotateToInterfaceOrientation:当设备处于纵向时返回 YES。SecondViewController 覆盖 this 方法以允许所有旋转。所有三个具体类都添加了一些彩色方块,以便能够通过将控制器推入/弹出UINavigationController. 到目前为止,我会说一个非常简单的场景。

如果您以纵向或横向方向握住设备,这就是我不仅想要实现的结果,而且也是期望的结果。在第一张图片中,您看到所有视图都是“直立的”,而在第二张图片中,您看到只有第二个视图控制器反向旋转了设备的方向。需要明确的是,应该可以从横向模式下的第二个视图导航到第三个视图,但是因为第三个仅支持纵向,所以它应该只以纵向显示。查看结果是否正常的最简单方法是查看载条的位置。

纵向模式下设备的预期视图方向 横向模式下设备的预期视图方向

但是这个问题在这里,因为实际结果完全不同。根据您旋转设备时所处的视图,以及根据您接下来导航到的视图,视图不会旋转(具体而言,该didOrientFromInterfaceOrientation:方法永远不会被调用)。如果您在第二个中处于横向并导航到第三个,它将具有与第二个相同的方向(=坏)。但是,如果您从第二个导航回第一个,屏幕将旋转到“强制”纵向模式,并且载体栏将位于设备的物理顶部,无论您如何握住它。视频更详细地展示了这一点。

横向模式下设备的实际视图方向

我的问题是双重的:

  1. 为什么第一个视图控制器旋转回来,而不是第三个?
  2. 当您只希望某些视图自动旋转而不希望其他视图自动旋转时,需要做什么才能从您的视图中获得正确的行为?

干杯,EP。

编辑:作为悬赏之前的最后手段,我完全重写了这个问题,使其更短、更清晰,并希望能更有吸引力地给出答案。

4

5 回答 5

8

简短的回答是您正在使用 UINavigationController,它不会像您希望的那样工作。来自 Apple 的文档:

为什么我的 UIViewController 不会随设备旋转?

您的 UITabBarController 或 UINavigationController 中的所有子视图控制器不同意共同的方向集。

为确保您的所有子视图控制器正确旋转,您必须为代表每个选项卡或导航级别的每个视图控制器实现 shouldAutorotateToInterfaceOrientation。每个人都必须同意相同的方向才能发生旋转。也就是说,对于相同的方向位置,它们都应该返回 YES。

您可以在此处阅读有关视图轮换问题的更多信息。

你必须为你想做的事情滚动你自己的视图/控制器堆栈管理。

于 2011-02-22T05:09:39.427 回答
5

在应用程序委托中创建一个布尔值来控制您想要的方向,例如创建一个布尔值来启用纵向,并在您的视图控制器中允许纵向通过共享应用程序启用它

在您的视图控制器中,您想要启用或禁用您想要的任何方向。

((APPNAMEAppDelegate *)[[UIApplication sharedApplication] delegate]).enablePortrait= NO;

在应用程序委托中。

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    NSLog(@"Interface orientations");
    if(!enablePortrait)
        return UIInterfaceOrientationMaskLandscape;
    return UIInterfaceOrientationMaskLandscape|UIInterfaceOrientationMaskPortrait;
}

每次旋转设备时都会触发这些方法,基于这些 BOOL 启用您想要的方向。

于 2012-12-04T09:12:11.597 回答
4

几年前有一个类似的问题,有很多答案。这是某人最近对该问题的回答:
是否有记录的方法来设置 iPhone 方向?

据我了解,这是很多人都遇到的问题,并且大多数黑客是解决它的唯一方法。如果您以前没有看过该线程,请查看该线程,看看是否有任何适合您的方法。

顺便说一句,不久前我在 shouldAutorotate 中调用某些东西时遇到了类似的问题,我添加了一些代码viewWillAppear来尝试修复它。老实说,我不记得它是否有效,并且我不再有 Mac 来尝试它,但我找到了代码并将其粘贴在这里以防它提供任何灵感。

- (void)viewWillAppear:(BOOL)animated{
  UIInterfaceOrientation o;
  switch ([UIDevice currentDevice].orientation) {
    case UIDeviceOrientationPortrait:
        o = UIInterfaceOrientationPortrait;
        break;
    case UIDeviceOrientationLandscapeLeft:
        o = UIInterfaceOrientationLandscapeLeft;
        break;
    case UIDeviceOrientationLandscapeRight:
        o = UIInterfaceOrientationLandscapeRight;
        break;
    default:
        break;
  }

  [self shouldAutorotateToInterfaceOrientation:o];
}
于 2011-02-20T07:38:29.870 回答
2

在 iOS 6 中,这已成为一个非常简单的问题。只需为要自动旋转的视图创建一个特殊类。然后,在你的 rootVC 中,添加这个。

-(BOOL)shouldAutorotate{
       BOOL should = NO;

       NSLog(@"%@", [self.viewControllers[self.viewControllers.count-1] class]);
       if ([self.viewControllers[self.viewControllers.count-1] isKindOfClass:[YourAutorotatingClass class]]) {
             should = YES;
       }


       return should;
}

我知道这是一个老问题,但我认为值得一提。

于 2013-02-10T21:51:09.773 回答
2

请勿使用此黑客,Apple 将根据“私人 API”的使用拒绝该应用程序

为了参考起见,我将我的答案留在这里,但私有 API 的使用不会越过审查委员会。我今天学到了一些东西:D 正如@younce 正确引用了Apple 文档,我想要的东西不能用UINavigationController 来实现。

我有两个选择。首先,我可以编写自己的导航控制器替代品,其中包含人们在这样做时会遇到的所有恐惧。其次,我可以使用 UIDevice 的一个未记录的功能(称为setOrientation:animated:

因为第二个很容易,所以我选择了那个。这就是我所做的。您需要一个类别来抑制有关 setter 不存在的编译器警告:

@interface UIDevice (UndocumentedFeatures) 
-(void)setOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated;
-(void)setOrientation:(UIInterfaceOrientation)orientation;
@end

然后你需要检查支持的方向viewWillAppear:。在此处使用的 UIDevice 方法旁边,您还可以通过显示模态视图控制器来强制纵向方向,但这会立即发生而不是动画,所以这是我的首选方式:

-(void)viewWillAppear:(BOOL)animated {
    UIDevice *device = [UIDevice currentDevice];
    UIDeviceOrientation realOrientation = device.orientation;

    if ([self shouldAutorotateToInterfaceOrientation:realOrientation]) {
        if (realOrientation != [UIApplication sharedApplication].statusBarOrientation) {

            // Resetting the orientation will trigger the application to rotate
            if ([device respondsToSelector:@selector(setOrientation:animated:)]) {
                [device setOrientation:realOrientation animated:animated];
            } else {
                // Yes if Apple changes the implementation of this undocumented setter,
                // we're back to square one.
            }
        }
    } else if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) {
        if ([device respondsToSelector:@selector(setOrientation:animated:)]) {

            // Then set the desired orientation
            [device setOrientation:UIDeviceOrientationPortrait animated:animated];

            // And set the real orientation back, we don't want to truly mess with the iPhone's balance system.
            // Because the view does not rotate on this orientation, it won't influence the app visually.
            [device setOrientation:realOrientation animated:animated];
        }
    }
}

诀窍是始终将内部设备方向保持在设备的“真实”方向。如果你开始改变它,你的应用程序的旋转将失去平衡。

但正如我现在所知,这只是让您的应用被拒绝的可靠方法。所以选项二只是一个糟糕的选择。重写那个 NavigationController,或者让你的所有视图都支持相同的方向设置。

干杯,EP。

于 2011-02-20T12:15:05.037 回答