68

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

我的整个应用程序只支持portrait模式。但是有一种叫做 " ChatView" 的视图,我想同时支持landscapeportrait模式。

我已将所需的设备旋转设置如下 -

在此处输入图像描述

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

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

但它无法旋转该视图。

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

而且在“ChatView”中还有一些对象,如按钮、文本字段,其框架是通过编程设置的。所以我想知道我是否还必须为横向模式设置所有这些对象的框架?

请帮我。

谢谢.....

4

14 回答 14

66

很简单,但效果很好。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
于 2014-09-20T19:35:30.337 回答
28

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

编辑

要子类化UINavigationController,请创建一个名为 eg 的新文件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

将您UINavigationController在主类 xib 中的类设置为CustomNavigationController. 希望对你有帮助。。

于 2013-07-04T09:11:34.860 回答
20

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

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

在 ChatView 中,应该是:

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

如果您需要在旋转后更改布局,您应该对您的子视图进行适当的更改

- (void)viewWillLayoutSubviews

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

于 2013-07-04T09:15:06.677 回答
17

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;
    }
}
于 2014-08-26T14:11:13.380 回答
4

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

当当前处于横向(启用所有方向)的 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 -> 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;
}
于 2015-02-25T09:54:45.753 回答
3

Swift 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根本不会被调用。

干得好!

如果当只有一个视图控制器应该支持一堆方向而其他视图控制器不支持时,您需要解决相反的问题,请对除此之外的每个视图控制器进行此更改。

希望这会有所帮助。

于 2017-02-23T20:14:55.253 回答
2

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

 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”。

于 2016-08-24T19:30:03.560 回答
2

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

假设你想要这个:

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

...然后(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
        }
    }
于 2016-10-04T17:38:42.197 回答
1

根据@iAnum 的回答,我启用了自动旋转和 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);
}

此处讨论的 VC 出现问题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:^{
            }];
        }];
    }
}
于 2014-06-18T12:05:21.390 回答
1

像这样创建 UINavigationController 的子类:

我的导航控制器.h

#import <UIKit/UIKit.h>

@interface MyNavigationController : UINavigationController

@end

我的导航控制器.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

假设您的视图控制器名为:ServicesVC

于 2014-11-26T19:42:34.853 回答
1

这是Swift中 Alexander ( 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
}}

对于您希望允许所有旋转的 ViewController,添加此功能:

override func canAutoRotate() -> Bool {
    return true
}
于 2015-08-15T04:23:34.777 回答
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];

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

于 2013-07-05T04:11:05.550 回答
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;
}   
于 2016-02-02T15:43:50.847 回答
0

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

#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
    if([AppDelegate isPad]) return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}
于 2016-08-09T06:07:56.110 回答