如何只允许单个UIViewController在风景和肖像方向旋转?

我的应用程序仅适用于iphone设备(iPhone 4和iPhone 5),并且仅支持ios 6

我的整个应用程序只支持portrait模式。 但是有一个叫“ ChatView ”的视图,我想支持landscapeportrait模式。

我已经设置了所需的设备旋转如下 –

在这里输入图像描述

我也试过下面的代码来支持“ChatView”中的旋转 –

 -(BOOL)shouldAutorotate { return YES; } -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscape; } 

但是它不能旋转那个视图。

我已经搜寻了很多,但无法find我的问题的解决scheme。

在“聊天视图”中还有一些对象,如button,框架设置为编程的文本框。 所以我想知道我应该不得不为景观模式设置所有这些对象的帧?

请帮帮我。

谢谢…..

我认为如果你只想支持一个viewcontroller旋转,这是不可能的,因为应用程序将遵循您在.plist文件中设置的方向。 您可以遵循的替代scheme是支持您的横向和纵向的应用程序,冻结所有viewcontrollers旋转为肖像,除了聊天视图。

编辑

UINavigationController ,请创build一个名称为CustomNavigationController的新文件,并将其作为UINavigationController子类。

.h文件

 #import <UIKit/UIKit.h> @interface CustomNavigationController : UINavigationController @end 

.m文件

 #import "CustomNavigationController.h" @interface CustomNavigationController () @end @implementation CustomNavigationController -(BOOL)shouldAutorotate { return NO; } -(UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return UIInterfaceOrientationIsPortrait(interfaceOrientation); } @end 

将您的主类xib中的UINavigationController类设置为CustomNavigationController。 希望它能帮助ypu ..

简单,但它工作得很好。 IOS 7.1和8

AppDelegate.h

 @property () BOOL restrictRotation; 

AppDelegate.m

 -(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { if(self.restrictRotation) return UIInterfaceOrientationMaskPortrait; else return UIInterfaceOrientationMaskAll; } 

视图控制器

 -(void) restrictRotation:(BOOL) restriction { AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate; appDelegate.restrictRotation = restriction; } 

viewDidLoad中

 [self restrictRotation:YES]; or NO 

你的视图控制器永远不会旋转到应用程序本身不支持的任何位置。 您应该启用所有可能的旋转,然后在视图中不应该旋转的控制器放置以下行

 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } 

在ChatView中,它应该是:

 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } 

如果您需要在轮换之后更改布局,则应该在您的子视图中实施适当的更改

 - (void)viewWillLayoutSubviews 

使用self.view.bounds来检查view的当前大小,因为self.view.frame在旋转后不会改变。

你要旋转的具体viewcontroller.m

添加这个方法:

 - (BOOL)canAutoRotate { return YES; } 

然后在你的AppDelegate.m

 - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { UIViewController *currentViewController = [self topViewController]; if ([currentViewController respondsToSelector:@selector(canAutoRotate)]) { NSMethodSignature *signature = [currentViewController methodSignatureForSelector:@selector(canAutoRotate)]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setSelector:@selector(canAutoRotate)]; [invocation setTarget:currentViewController]; [invocation invoke]; BOOL canAutorotate = NO; [invocation getReturnValue:&canAutorotate]; if (canAutorotate) { return UIInterfaceOrientationMaskAll; } } return UIInterfaceOrientationMaskPortrait; } - (UIViewController *)topViewController { return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; } - (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController { if ([rootViewController isKindOfClass:[UITabBarController class]]) { UITabBarController* tabBarController = (UITabBarController*)rootViewController; return [self topViewControllerWithRootViewController:tabBarController.selectedViewController]; } else if ([rootViewController isKindOfClass:[UINavigationController class]]) { UINavigationController* navigationController = (UINavigationController*)rootViewController; return [self topViewControllerWithRootViewController:navigationController.visibleViewController]; } else if (rootViewController.presentedViewController) { UIViewController* presentedViewController = rootViewController.presentedViewController; return [self topViewControllerWithRootViewController:presentedViewController]; } else { return rootViewController; } } 

泰德的答案与挪威的亚历山大所提到的问题一致。 但我认为这个问题不是亚历山大解释的方式,

当用户点击后退button后,当前处于横向(所有方向启用)的ViewController B返回到ViewController A(仅限纵向)时,supportedInterfaceOrientationsForWindow不会被调用,并且ViewController A以横向

实际上,当用户点击后退button后,ViewController B当前处于横向(所有方向启用)返回到ViewController A(仅限纵向),Appdelegate

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; 

被召唤。 但仍然根视图控制器是ViewController B(该旋转启用视图控制器),ViewController A不回到纵向,因为ViewController B仍然返回

 -(BOOL)shouldAutorotate{ return YES; } 

所以当你按下返回button时,在ViewController B中的“shouldAutorotate – > NO”,然后ViewController A会变成纵向。 这就是我所做的

 @property (nonatomic, assign) BOOL canAutoRotate; #pragma mark - Public methods - (BOOL)canAutoRotate { return _canAutoRotate; } #pragma mark - Button actions - (void)backButtonPressed:(UIButton *)sender { _canAutoRotate = NO; (...) } #pragma mark - Init - (id)init{ if(self=[super init]) { _canAutoRotate = YES; } return self; } 

基于@ iAnum的回答,我已经启用了autorotate和UIViewController类的检测。

这是因为否则,进入和退出“特殊视图控制器”将不能纠正为纵向,并且您将陷入不受支持的方向。

我只有一个视图支持横向,所以我只是硬编码在自定义导航视图控制器中:

 -(BOOL)shouldAutorotate { return YES; } -(NSUInteger)supportedInterfaceOrientations { //Access the current top object. UIViewController *viewController = [self.viewControllers lastObject]; //Is it one of the landscape supported ones? if ([viewController isMemberOfClass:[SpecialViewController class]]) { return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight; } else return UIInterfaceOrientationMaskPortrait; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { //Access the current top object. UIViewController *viewController = [self.viewControllers lastObject]; //Is it one of the landscape supported ones? if ([viewController isMemberOfClass:[SpecialViewController class]]) { return interfaceOrientation; } else return UIInterfaceOrientationIsPortrait(interfaceOrientation); } 

有一个问题突然出现风险投资家在这里讨论https://stackoverflow.com/a/15057537/1277350在景观按下时甚至不会调用定位方法,所以你必须通过显示和解雇模态视图。;

然后记住,如果你想让willShowViewController触发,你需要设置self.delegate = self并将UINavigationControllerDelegate和下面的代码一起添加到你的自定义导航控制器中。

 - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return UIInterfaceOrientationPortrait; } - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { UIApplication* application = [UIApplication sharedApplication]; if (application.statusBarOrientation != UIInterfaceOrientationPortrait) { UIViewController *c = [[UIViewController alloc]init]; [c.view setBackgroundColor:[UIColor clearColor]]; [navigationController presentViewController:c animated:NO completion:^{ [self dismissViewControllerAnimated:YES completion:^{ }]; }]; } } 

使UINavigationController的子类如下所示:

MyNavigationController.h

 #import <UIKit/UIKit.h> @interface MyNavigationController : UINavigationController @end 

MyNavigationController.m

 #import "MyNavigationController.h" #import "ServicesVC.h" @implementation MyNavigationController -(BOOL)shouldAutorotate{ return YES; } -(NSUInteger)supportedInterfaceOrientations{ if ([[self.viewControllers lastObject] isKindOfClass:[ServicesVC class]]) { return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight; } return UIInterfaceOrientationMaskAll; } @end 

假设您的viewcontroller被命名为:ServicesVC

这里是亚历山大( https://stackoverflow.com/posts/25507963/revisions )在Swift中的答案:

 func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int { var currentViewController: UIViewController? = self.topViewController() if currentViewController != nil && currentViewController!.canAutoRotate() { return Int(UIInterfaceOrientationMask.All.rawValue) } return Int(UIInterfaceOrientationMask.Portrait.rawValue) } func topViewController() -> UIViewController? { if UIApplication.sharedApplication().keyWindow != nil { return self.topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!) } return nil } func topViewControllerWithRootViewController(rootViewController: UIViewController?) -> UIViewController? { if rootViewController == nil { return nil } if rootViewController!.isKindOfClass(UITabBarController) { var tabBarController: UITabBarController = (rootViewController as? UITabBarController)! return self.topViewControllerWithRootViewController(tabBarController.selectedViewController) } else { if rootViewController!.isKindOfClass(UINavigationController) { var navigationController: UINavigationController = (rootViewController as? UINavigationController)! return self.topViewControllerWithRootViewController(navigationController.visibleViewController) } else { if (rootViewController!.presentedViewController != nil) { var presentedViewController: UIViewController = rootViewController!.presentedViewController! return self.topViewControllerWithRootViewController(presentedViewController) } else { return rootViewController } } } } 

另外,您需要在AppDelegate.swift中添加以下代码片段:

 extension UIViewController { func canAutoRotate() -> Bool { return false }} 

而对于你想允许所有旋转的ViewControllers,添加这个函数:

 override func canAutoRotate() -> Bool { return true } 

我不确定这个问题的历史(现在是iOS 10的时间表),但是最简单的解决scheme是在2016年10月发布的。

假设你想这样做:

  1. 支持iOS 7和更新版本(包括iOS 10)
  2. 一些视图控制器应该支持所有的方向,其他视图控制器应该支持方向的一个子集。 我的意思是例子:一个视图控制器应该只支持肖像,而其他视图控制器应该支持所有的方向
  3. 所有视图控制器必须在支持旋转的情况下自动旋转(也就是说,您不希望在视图控制器中修复此问题的代码)
  4. 支持在XIBs / NIBs / Storyboard中添加UINavigationController ,而不必对它们做任何事情

…然后(IMO)最简单的解决办法是做一个UINavigationControllerDelegate ,而不是子类UINavigationController(这违反了上述假设4)。

当我解决这个问题时,我决定让我的第一个ViewController成为一个UINavigationControllerDelegate 。 该视图控制器将自己设置为导航控制器的委托,并返回允许的方向。 在我的情况下,默认是所有的方向是允许的,肖像是首选,但在一个特定的情况下,只有肖像是允许的。 下面的代码来自Swift 3 / XCode 8:

  class iPhoneStartViewController: UIViewController { var navInterfaceOrientationMask: UIInterfaceOrientationMask? var navInterfaceOrientationPreferred: UIInterfaceOrientation! = .portrait override func viewDidLoad() { super.viewDidLoad() self.navigationController?.delegate = self } @IBAction func cameraButtonPressed(_ sender: AnyObject) { if PermissionsHelper.singleton().photosPermissionGranted() == false { self.navInterfaceOrientationMask = nil // default is: all orientations supported self.performSegue(withIdentifier: "segueToPhotoAccess", sender: self) } else { self.navInterfaceOrientationMask = .portrait // this stops the next view controller from being to rotate away from portrait self.performSegue(withIdentifier: "segueToCamera", sender: self) } } } // lock orientation to portrait in certain cases only. Default is: all orientations supported extension iPhoneStartViewController : UINavigationControllerDelegate { public func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask { if let mask = self.navInterfaceOrientationMask { return mask } else { return .all } } public func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation { return self.navInterfaceOrientationPreferred } } 

斯威夫特3犹太版本

我在这里只是为了某个人有这个问题。

苹果的 supportedInterfaceOrientations 的文档说:

当用户更改设备方向时,系统在根视图控制器或填充窗口的最顶层呈现视图控制器上调用此方法。 如果视图控制器支持新的方向,窗口和视图控制器将旋转到新的方向。 只有在视图控制器的shouldAutorotate方法返回true时,才会调用此方法。

简而言之,您必须在根视图控制器中重写supportedInterfaceOrientations ,以便返回其顶部子视图控制器的值,否则返回默认值。

所以你应该做的是检查应用程序是否支持所有模式(转到目标常规设置或Info.plist中的部署信息),找出你的根视图控制器的类。 它可以是通用的UIViewController,UINavigationController,UITabBarController或一些自定义类。 你可以通过这种方式来查看:

 dump(UIApplication.shared.keyWindow?.rootViewController) 

或者你喜欢的任何其他方式。

让它是一些CustomNavigationController 。 所以你应该像这样覆盖supportedInterfaceOrientations

 class CustomNavigationController: UINavigationController { override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown } } 

在任何应该只支持纵向方向的视图控制器中,通过这种方式覆盖supportedInterfaceOrientations

 class ChildViewController: UIViewController { override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } } 

那么不要忘记检查你的根视图控制器和最顶层的视图控制器的shouldAutorotate是否已经返回true 。 如果不是,请将其添加到类定义中:

 override var shouldAutorotate: Bool { return true } 

否则supportedInterfaceOrientations将不会被调用。

干得好!

如果只有一个视图控制器应该支持一组方向,而另一些视图控制器不支持,则需要修复相反的问题,否则请对每个视图控制器进行更改,但是这个视图控制器不能。

希望这会有所帮助。

我也有同样的情况。 所以我将UINavigationController分类到CustomNavigationController中,在这个CustomNavigationController中,我写了

 #define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 ) #define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 ) #pragma mark - Rotation #ifdef IOS_OLDER_THAN_6 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{ return (toInterfaceOrientation == UIInterfaceOrientationPortrait); } #endif #ifdef IOS_NEWER_OR_EQUAL_TO_6 -(BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait;; } #endif 

我用这个CustomNavigationController而不是现有的NavigationController。

然后在视图控制器中,你必须在LandScape Orientation中显示LandScapeView,我写道

 #pragma mark - Rotation #ifdef IOS_OLDER_THAN_6 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{ return (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight | toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft); } #endif #ifdef IOS_NEWER_OR_EQUAL_TO_6 -(BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft; } #endif 

在CustomNavigationController里面,我展示了这个视图控制器,并没有推入导航堆栈。 所以LandScapeView出现在LandScape的定位中。

 LandScapeView *graph = [[LandScapeView alloc]init....]; [self presentViewController:graph animated:YES completion:nil]; 

在“项目设置”中的“ 支持的界面方向”中,我没有更改任何内容。

//将此方法粘贴到应用程序的deligate类中

 - (UIInterfaceOrientationMask)application:(UIApplication )application supportedInterfaceOrientationsForWindow:(UIWindow )window { if ([self.window.rootViewController.presentedViewController isKindOfClass: [_moviePlayerController class]]) { if (self.window.rootViewController.presentedViewController) return UIInterfaceOrientationMaskAll; else return UIInterfaceOrientationMaskPortrait; } else return UIInterfaceOrientationMaskPortrait; } 

如果应用程序支持从IOS7IOS9使用此代码的方向:

 #if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000 - (NSUInteger)supportedInterfaceOrientations #else - (UIInterfaceOrientationMask)supportedInterfaceOrientations #endif { if([AppDelegate isPad]) return UIInterfaceOrientationMaskAll; else return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; } 

我知道这个问题是非常古老的,但它需要一个更新的答案。 实现这个结果最简单也是最正确的方法是在您的应用程序设置中启用纵向和横向。 然后将此代码添加到您的应用程序委托:

  func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask { if let navigationController = self.window?.rootViewController as? UINavigationController { if navigationController.visibleViewController is INSERTYOURVIEWCONTROLLERHERE { return UIInterfaceOrientationMask.All } else { return UIInterfaceOrientationMask.Portrait } } return UIInterfaceOrientationMask.Portrait } 

不要忘记用您的视图控制器replace“INSERTYOURVIEWCONTROLLERHERE”。