iOS 6:如何限制一些视图的肖像,并允许他人旋转?
我有一个iPhone应用程序,它使用UINavigationController来呈现一个向下钻取的界面:第一个视图,然后是另一个视图,深达四层。 我希望将前三个视图限制为纵向,只允许最后一个视图旋转到横向。 当从第四个视图返回到第三个视图,并且第四个视图处于横向时,我希望所有的东西都旋转回肖像。 
 在iOS 5中,我简单地定义了shouldAutorotateToInterfaceOrientation:在我的每个视图控制器中为允许的方向返回YES。 一切工作如上所述,包括即使从视图控制器#4到#3返回时横向保持设备也返回肖像。 
在iOS 6中,所有的视图控制器旋转到横向,打破那些不意味着。 iOS 6发行说明说
更多的责任是转移到应用程序和应用程序委托。 现在,iOS容器(如
UINavigationController)不会咨询他们的孩子,以确定他们是否应该自动旋转。 […]系统每当设备旋转时或每当视图控制器呈现全屏模式演示风格时,都会询问其支持的接口方向的最顶级全屏视图控制器(通常是根视图控制器)。 此外,只有当这个视图控制器从其shouldAutorotate方法返回YES时,才会检索支持的方向。 […]系统通过将应用程序的supportedInterfaceOrientationsForWindow:方法返回的值与最顶级的全屏控制器的supportedInterfaceOrientations方法返回的值相交来确定是否支持方向。
 所以我subclassed UINavigationController ,给了我的MainNavigationController布尔属性landscapeOK并用它来返回在supportedInterfaceOrientations允许的方向。 然后在我的每个视图控制器的viewWillAppear:方法,我有这样的一行 
  [(MainNavigationController*)[self navigationController] setLandscapeOK:YES]; 
 告诉我的MainNavigationController所需的行为。 
问题来了:如果我现在在纵向模式下导航到我的第四个视图,并翻转手机,它会旋转到横向。 现在我按下后退button返回到我的第三个视图,这应该只是工作肖像。 但是它不会回转。 我该如何做到这一点?
我试过了
  [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait] 
 在我的第三个视图控制器的viewWillAppear方法,但它什么都不做。 这是错误的方法来调用,或者错误的地方来调用它,或者我应该以完全不同的方式来实现整个事情吗? 
 我遇到了同样的问题,并find了适合我的解决scheme。 为了使其工作,在你的UINavigationController中实现- (NSUInteger)supportedInterfaceOrientations是不够的。 你也需要在你的控制器#3中实现这个方法,这是第一个在popup控制器#4之后才是肖像的方法。 所以,我在我的UINavigationController中有以下代码: 
 - (BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { if (self.isLandscapeOK) { // for iPhone, you could also return UIInterfaceOrientationMaskAllButUpsideDown return UIInterfaceOrientationMaskAll; } return UIInterfaceOrientationMaskPortrait; } 
在视图控制器#3中添加以下内容:
 - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } 
你不需要添加任何东西到你的视图控制器#1,#2和#4。 这对我有用,我希望它能帮助你。
添加一个CustomNavigationController
重写这些方法:
 -(BOOL)shouldAutorotate { return [[self.viewControllers lastObject] shouldAutorotate]; } -(NSUInteger)supportedInterfaceOrientations { return [[self.viewControllers lastObject] supportedInterfaceOrientations]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation]; } 
现在在plist中添加所有的方向

在视图控制器中只添加需要的:
 -(BOOL)shouldAutorotate { return YES; } -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } 
这些方法覆盖导航控制器方法
在对所有关于SO的类似问题的每一个答案进行审查后,没有任何答案为我工作,但他们给了我一些想法。 以下是我最终解决问题的方法:
首先,确保项目目标中支持的界面方向包含所需的旋转视图的所有方向。

 接下来,做一个UINavigationController的类别(因为苹果说不要inheritance它): 
 @implementation UINavigationController (iOS6AutorotationFix) -(BOOL)shouldAutorotate { return [self.topViewController shouldAutorotate]; } @end 
 将您想要旋转的类别和视图控制器(我将调用RotatingViewController )导入到最高级别的视图控制器,该视图控制器应该包含您的导航控制器。 在该视图控制器中,执行如下所示的操作。 请注意,这不应该是你想要旋转的视图控制器。 
 -(BOOL)shouldAutorotate { BOOL shouldRotate = NO; if ([navigationController.topViewController isMemberOfClass:[RotatingViewController class]] ) { shouldRotate = [navigationController.topViewController shouldAutorotate]; } return shouldRotate; } 
 最后,在您的RotatingViewController ,执行shouldAutorotate和supportedInterfaceOrientations ,如下所示: 
 -(BOOL)shouldAutorotate { // Preparations to rotate view go here return YES; } -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAllButUpsideDown; // or however you want to rotate } 
你需要这样做的原因是因为iOS 6控制旋转到根视图控制器而不是顶视图控制器。 如果您希望单个视图的旋转与堆栈中其他视图的行为不同,则需要在根视图控制器中为其编写特定的案例。
我没有足够的声望评论@ Brian的答案,所以我会在这里添加我的笔记。
Brian提到iOS6给了rootViewController旋转控制 – 这不仅可以是上面提到的UINavigationController,也可以是UITabBarController,这对我来说也是如此。 我的结构如下所示:
-  的UITabBarController
-   UINavigationController的
- UIViewControllers …
 
-   UINavigationController的
- UIViewControllers …
 
 
-   UINavigationController的
所以我首先在自定义的UITabBarController中添加了方法,然后在自定义的UINavigationController中添加了方法,最后在特定的UIViewController中添加了方法。
来自UITabBarController和UINavigationController的示例:
 - (BOOL)shouldAutorotate { return [self.viewControllers.lastObject shouldAutorotate]; } - (NSUInteger)supportedInterfaceOrientations { return [self.viewControllers.lastObject supportedInterfaceOrientations]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { return [self.viewControllers.lastObject shouldAutorotateToInterfaceOrientation:toInterfaceOrientation]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [self.viewControllers.lastObject preferredInterfaceOrientationForPresentation]; } 
 我想对自己的问题给出部分答案。 我发现下面一行代码,在我的第三个UIViewController的viewWillAppear方法中使用: 
 [[UIDevice currentDevice] performSelector:NSSelectorFromString(@"setOrientation:") withObject:(id)UIInterfaceOrientationPortrait]; 
但我不太喜欢这个解决scheme。 它使用一个技巧来分配一个只读属性,根据Apple文档,该属性表示设备的物理方向。 这就像告诉iPhone跳到用户手中正确的方向。
我很想把它放在我的应用程序,因为它只是工作。 但是感觉不对,所以我想留下一个干净的解决scheme。
这是我在ios 6.0中用于定向支持
 -(BOOL)shouldAutorotate{ return YES; } - (NSUInteger)supportedInterfaceOrientations{ return UIInterfaceOrientationMaskAll; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{ return UIInterfaceOrientationPortrait; } 
因为这是一个高度看待的线程。 我想我会添加我认为是最简单的答案。 这适用于ios8及以上
 -(BOOL)shouldAutorotate { return YES; } 
和
 -(UIInterfaceOrientationMask)supportedInterfaceOrientations{ return UIInterfaceOrientationMaskPortrait; } 
而已。 请享用!
哦,我的ViewControllers被embedded到一个导航控制器中,我不需要任何子类或configuration。
这可能不适用于所有人,但对我来说这很好。 而不是实施…
 [(MainNavigationController*)[self navigationController] setLandscapeOK:YES]; 
 在viewWillAppear在我所有的控制器中,我决定通过重写UINavigationControllerDelegate方法navigationController:willShowViewController:animated:来集中这个过程在我的UINavigationController子类中navigationController:willShowViewController:animated: 
 - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { self.previousVCLandscapeOK = self.isLandscapeOK; // Store the current VC's orientation preference before pushing on the new VC so we can set this again from within the custom "back" method self.isLandscapeOK = NO; // Set NO as default for all VC's if ([viewController isKindOfClass:[YourViewController class]]) { self.isLandscapeOK = YES; } } 
我发现这个代理方法不会被调用时,从导航堆栈popup一个VC。 这对我来说不是问题,因为我在我的UINavigationController子类中处理后面的function,这样我就可以为特定的VC设置正确的导航栏button和动作,像这样…
 if ([viewController isKindOfClass:[ShareViewController class]]) { UIButton* backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 57, 30)]; [backButton setImage:[UIImage imageNamed:@"back-arrow"] forState:UIControlStateNormal]; [backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside]; UIBarButtonItem* backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton]; viewController.navigationItem.leftBarButtonItem = backButtonItem; UIImageView* shareTitle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"share-title"]]; [shareTitle setContentMode:UIViewContentModeScaleAspectFit]; [shareTitle setFrame:CGRectMake(0, 0, shareTitle.frame.size.width - 10, shareTitle.frame.size.height - 10)]; viewController.navigationItem.titleView = shareTitle; } else if(...) { ... } 
 这是我的back方法看起来像处理从堆栈中popupVC并设置适当的旋转首选项… 
 - (void)back { self.isLandscapeOK = self.previousVCLandscapeOK; self.previousVCLandscapeOK = NO; [self popViewControllerAnimated:YES]; } 
所以,正如你所看到的,基本上所有发生的事情是我第一次设定我的两个属性…
 @property (nonatomic) BOOL isLandscapeOK; @property (nonatomic) BOOL previousVCLandscapeOK; 
 在navigationController:willShowViewController:animated:这将决定什么样的支持的方向是即将展示的VC内。 当popup一个VC时,我调用了自定义的“后退”方法,然后将isLandscapeOK设置为通过之前的VCLandscapeOK值存储的内容。 
正如我所说的,这可能不适用于每个人,但它对我来说很好,我不必担心向我的每个视图控制器添加代码,我可以将它全部集中在UINavigationController子类中。
希望这可以帮助像我这样的人。 谢谢,杰里米。
 转到Info.plist文件并进行更改 
你想强制iOS 6的应用程序的肖像只有那么你可以添加到UIViewController子类下方的方法
 - (BOOL)shouldAutorotate { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { return YES; } else { return NO; } } - (NSUInteger)supportedInterfaceOrientations { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { return UIInterfaceOrientationMaskAll; } else { return UIInterfaceOrientationMaskPortrait; } } 
除了一个,我想让所有的VC都locking为纵向。 这是为我工作。
- 在plist文件中添加对所有方向的支持。
- 
在根视图控制器中,检测窗口顶部的视图控制器的types,并相应地在supportedInterfaceOrientations方法中设置应用的方向。 例如,我需要我的应用程序只有当webview在堆栈顶部时才能旋转。 以下是我在rootVC中添加的内容: -(NSUInteger)supportedInterfaceOrientations { UIViewController *topMostViewController = [[Utils getAppDelegate] appNavigationController].topViewController; if ([topMostViewController isKindOfClass:[SVWebViewController class]]) { return UIInterfaceOrientationMaskAllButUpsideDown; } return UIInterfaceOrientationMaskPortrait; }
我没有足够的声望回答@Ram S在@micmdk答复下的问题,所以我会在这里添加我的笔记。
当您使用UITabbarController时 ,请尝试将@ micmdk的代码中的self.viewControllers.lastObject更改为self.selectedViewController,如下所示:
 - (BOOL)shouldAutorotate { return [self.selectedViewController shouldAutorotate]; } - (NSUInteger)supportedInterfaceOrientations { return [self.selectedViewController supportedInterfaceOrientations]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { return [self.selectedViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [self.selectedViewController preferredInterfaceOrientationForPresentation]; } 
我面临同样的问题。 解决了我的问题,如下所示。
 如果您使用UINavigationController来推视图控制器,那么你必须设置下面的方法。 
扩展UINavigationController {
 override open var shouldAutorotate: Bool { if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))! { return true } return false } override open var supportedInterfaceOrientations: UIInterfaceOrientationMask { if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))! { return .portrait } return .landscapeRight } override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))! { return .portrait } return .landscapeRight } 
}
 代替LoginViewController使用你想要显示的UIViewController 。 在我的情况下,我想在Portrait模式下以Portrait模式显示其他ViewControllers中的LoginViewController 。 
请使用下面的方法来解决这个问题
 - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } 
只返回你想要的方向!