如何只允许单个UIViewController在横向和纵向方向上旋转?

时间:2013-07-04 08:57:20

标签: iphone ios objective-c uiviewcontroller

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

我的整个应用只支持portrait模式。但是有一个名为“ChatView”的视图,我希望同时支持landscapeportrait模式。

我已按如下方式设置所需的设备旋转 -

enter image description here

我还尝试使用以下代码来支持“ChatView”中的旋转 -

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

但它无法旋转那个视图。

我已经搜索了很多,但无法找到我的问题的解决方案。

并且在“ChatView”中还有一些对象,如按钮,文本字段,其帧设置为programmaticaly。所以我想知道我是否还必须为横向模式设置所有这些对象的帧?

请帮帮我。

感谢.....

13 个答案:

答案 0 :(得分:62)

简单但工作得很好。 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;
}

的ViewController

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

viewDidLoad中

[self restrictRotation:YES]; or NO

答案 1 :(得分:28)

我认为如果你只想支持一个viewcontroller轮换,那么因为应用程序将遵循你在.plist文件中设置的方向,所以不可能。您可以遵循的替代方案是支持横向和纵向的应用程序,将所有视图控制器旋转冻结为纵向,聊天视图除外。

修改

要创建一个名为UINavigationController的新文件,请创建一个名称为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 ..

答案 2 :(得分:21)

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

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

在ChatView中,它应该是:

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

如果您需要在轮换后更改布局,则应在

中对子视图实施适当的更改
- (void)viewWillLayoutSubviews

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

答案 3 :(得分:15)

表示您要旋转的特定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;
    }
}

答案 4 :(得分:3)

特德的回答与挪威亚历山大提到的问题很吻合。 但我认为这个问题并没有像亚历山大解释的那样发生,

  

当ViewController B当前处于横向状态时(全部   已启用方向)返回ViewController A.(肖像   只有)用户点击后退按钮后,   supportedInterfaceOrientationsForWindow不会被调用   ViewController A以横向

结束

实际上,当用户点击后退按钮后,当前处于横向(启用了所有方向)的ViewController B返回ViewController A(仅限肖像)时,Appdelegate

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;

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

-(BOOL)shouldAutorotate{

    return YES;
}

因此当您按下返回按钮返回时,ViewController B中的“shouldAutorotate - &gt; 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;
}

答案 5 :(得分:1)

根据@ iAnum的回答,我已经启用了自动旋转和UIViewController类检测。

这是因为否则转入和转出特殊视图控制器&#34;不会对纵向方向进行纠正,而且你会被困在一个不受支持的方向。

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

-(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:^{
            }];
        }];
    }
}

答案 6 :(得分:1)

创建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

答案 7 :(得分:1)

以下是亚历山大(https://stackoverflow.com/posts/25507963/revisions)在斯威夫特中的答案:

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
}

答案 8 :(得分:1)

我不确定此问题的历史(现在= iOS 10时间范围),但在2016年10月发布此时,最简单的解决方案丢失了。

假设你想要这个:

  1. 仅支持 iOS 7 和更新版(包括iOS 10)
  2. 某些视图控制器应支持所有方向,其他视图控制器应支持方向的子集。 我的意思是:一个视图控制器应该只支持肖像,而所有其他视图控制器应该支持所有方向
  3. 如果所有视图控制器都支持旋转,则必须自动旋转(这意味着,您不希望在视图控制器中修复此问题的代码)
  4. 支持在XIB / NIB / Storyboard中添加UINavigationController,而无需对其进行任何操作
  5. ...然后(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
            }
        }
    

答案 9 :(得分:0)

我有同样的情况。所以我将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 Orientation。

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

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

如果应用程序支持从 IOS7 IOS9 ,请使用此代码进行定位:

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

答案 12 :(得分:0)

我知道这些问题已经很老了但需要更新的答案。实现此结果的最简单,最正确的方法是在应用程序设置中启用纵向和横向。然后将此代码添加到您的应用代理:

 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
}

别忘了用视图控制器替换“INSERTYOURVIEWCONTROLLERHERE”。