如何在iOS 8中强制查看控制器方向?

Ras*_*ick 144 objective-c uinavigationcontroller autorotate ios ios8

在iOS 8之前,我们将下面的代码与supportedInterfaceOrientationsshouldAutoRotate委托方法结合使用,以强制应用程序方向指向任何特定方向.我使用下面的代码段以编程方式将应用程序旋转到所需的方向.首先,我正在改变状态栏方向.然后只显示并立即关闭模态视图会将视图旋转到所需的方向.

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
UIViewController *c = [[UIViewController alloc]init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];
Run Code Online (Sandbox Code Playgroud)

但这在iOS 8中失败了.而且,我已经看到堆栈溢出的一些答案,人们建议我们应该始终从iOS 8开始避免这种方法.

更具体地说,我的应用程序是一种通用类型的应用程序.总共有三个控制器.

  1. First View控制器 - 它应该支持iPad中的所有方向,并且只支持iPhone中的纵向(主页按钮).

  2. 第二视图控制器 - 它应该只支持所有条件下的横向

  3. 第三视图控制器 - 它应该只支持所有条件下的风景

我们使用导航控制器进行页面导航.从第一个视图控制器,在按钮单击操作上,我们在堆栈上推送第二个.因此,当第二个视图控制器到达时,无论设备方向如何,应用程序都应仅锁定横向.

下面是我shouldAutorotatesupportedInterfaceOrientations第二和第三视图控制器中的方法.

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}
Run Code Online (Sandbox Code Playgroud)

对于这种或任何更好的方法来锁定iOS 8的特定方向的视图控制器是否有任何解决方案.请帮忙!!

Sun*_*hah 305

对于iOS 7 - 10:

Objective-C的:

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];
[UINavigationController attemptRotationToDeviceOrientation];
Run Code Online (Sandbox Code Playgroud)

斯威夫特3:

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()
Run Code Online (Sandbox Code Playgroud)

只需- viewDidAppear:在显示的视图控制器中调用它.

  • 这不是*私有API.这是*不安全*使用API​​.您没有使用任何私有方法,而是使用"内部事物".如果Apple更改"方向"的值,则会失败.更糟糕的是:如果Apple改变了"方向"值的含义,你就不知道你正在改变什么,难以设定价值. (60认同)
  • 要禁用动画,请将`[UIView setAnimationsEnabled:NO];`放在`viewWillAppear`和`[UIView setAnimationsEnabled:YES];```viewDidAppear`中,相关:http://stackoverflow.com/a/6292506/88597 (3认同)
  • 不错的黑客,但问题是,在设置新的方向值(叹气)后,没有触发didRotateFromInterfaceOrientation (3认同)
  • 在iOS 9.2中,这只是改变方向而不是锁定. (2认同)
  • 对于每个人,在90%的时间内表现良好,而在其他10%的时间内表现良好,请在设置方向键后调用此方法: (2认同)

Kor*_*ton 92

如果你在一个UINavigationController或多个里面,方向旋转会有点复杂UITabBarController.问题是如果视图控制器嵌入其中一个控制器中,导航或标签栏控制器优先,并决定自动旋转和支持的方向.

我在UINavigationController和UITabBarController上使用以下2个扩展,以便嵌入其中一个控制器的视图控制器可以做出决定.

为视图控制器提供动力!

斯威夫特2.3

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> Int {
        return visibleViewController.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

extension UITabBarController {
    public override func supportedInterfaceOrientations() -> Int {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特3

extension UINavigationController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return visibleViewController?.supportedInterfaceOrientations ?? super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        return visibleViewController?.shouldAutorotate ?? super.shouldAutorotate
    }
}

extension UITabBarController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate
        }
        return super.shouldAutorotate
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以覆盖该supportedInterfaceOrientations方法,或者您可以shouldAutoRotate在要锁定的视图控制器中覆盖,否则您可以忽略其他视图控制器中要覆盖应用程序plist中指定的默认方向行为的覆盖

禁用旋转

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}
Run Code Online (Sandbox Code Playgroud)

锁定特定方向

class ViewController: UIViewController {
    override func supportedInterfaceOrientations() -> Int {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
}
Run Code Online (Sandbox Code Playgroud)

从理论上讲,这应该适用于所有复杂的视图控制器层次结构,但我注意到UITabBarController存在问题.出于某种原因,它想要使用默认方向值.如果您有兴趣了解如何解决某些问题,请参阅以下博文:

锁定屏幕旋转

  • 这是Swift和ObjC的一个很好的解决方案.不明白为什么人们投票.你有了主意,然后编写代码很容易.为什么要抱怨? (17认同)
  • 针对Swift的向下标记仅回答Objective-C问题. (7认同)
  • 我知道这是一篇很老的帖子,但你会把扩展代码放在哪里? (2认同)
  • @Krodak,在扩展中尝试将" - > Int"更改为" - > UIInterfaceOrientationMask".为我做了诀窍. (2认同)
  • 这个想法和代码是完美的,我喜欢它,但是在使用UINavigationController时会出现问题,并且从横向显示的UIViewController返回到必须以纵向显示的UIViewController.有任何想法吗? (2认同)

Vin*_*hop 23

这对我有用:

https://developer.apple.com/library//ios/documentation/UIKit/Reference/UIViewController_Class/index.html#//apple_ref/occ/clm/UIViewController/attemptRotationToDeviceOrientation

在viewDidAppear:方法中调用它.

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [UIViewController attemptRotationToDeviceOrientation];
}
Run Code Online (Sandbox Code Playgroud)

  • 非常有用,如果设备已经旋转,您需要旋转视图控制器 (3认同)
  • 很好的答案.当与接受的答案结合使用时,每次在Swift和iOS 9+中都适合我. (2认同)

小智 20

我发现如果它是一个呈现的视图控制器,你可以覆盖 preferredInterfaceOrientationForPresentation

迅速:

override func supportedInterfaceOrientations() -> Int {
  return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
  return UIInterfaceOrientation.LandscapeLeft
}

override func shouldAutorotate() -> Bool {
  return false
}
Run Code Online (Sandbox Code Playgroud)

  • 似乎接受的答案只会触发方向改变为景观.你在这里展示的是如何*强制*视图控制器*仅*在横向,而不影响呈现视图控制器(这正是我需要的).谢谢. (4认同)

Ale*_*ano 15

这种方式适用于Swift 2 iOS 8.x:

PS(这种方法不需要在每个viewController上覆盖定向函数,比如shouldautorotate,只需要AppDelegate上的一个方法)

检查项目常规信息中的"需要全屏". 在此输入图像描述

所以,在AppDelegate.swift上创建一个变量:

var enableAllOrientation = false
Run Code Online (Sandbox Code Playgroud)

所以,还把这个功能:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
        if (enableAllOrientation == true){
            return UIInterfaceOrientationMask.All
        }
        return UIInterfaceOrientationMask.Portrait
}
Run Code Online (Sandbox Code Playgroud)

因此,在项目的每个类中,您都可以在viewWillAppear中设置此var:

override func viewWillAppear(animated: Bool)
{
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        appDelegate.enableAllOrientation = true
}
Run Code Online (Sandbox Code Playgroud)

如果您需要根据设备类型进行选择,可以执行以下操作:

override func viewWillAppear(animated: Bool)
    {
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        switch UIDevice.currentDevice().userInterfaceIdiom {
        case .Phone:
        // It's an iPhone
           print(" - Only portrait mode to iPhone")
           appDelegate.enableAllOrientation = false
        case .Pad:
        // It's an iPad
           print(" - All orientation mode enabled on iPad")
           appDelegate.enableAllOrientation = true
        case .Unspecified:
        // Uh, oh! What could it be?
           appDelegate.enableAllOrientation = false
        }
    }
Run Code Online (Sandbox Code Playgroud)


gbk*_*gbk 11

首先 - 这是一个坏主意,一般来说,您的应用程序架构出现问题,但是sh..t happens,如果是这样,您可以尝试制作如下内容:

final class OrientationController {

    static private (set) var allowedOrientation:UIInterfaceOrientationMask = [.all]

    // MARK: - Public

    class func lockOrientation(_ orientationIdiom: UIInterfaceOrientationMask) {
        OrientationController.allowedOrientation = [orientationIdiom]
    }

    class func forceLockOrientation(_ orientation: UIInterfaceOrientation) {
        var mask:UIInterfaceOrientationMask = []
        switch orientation {
            case .unknown:
                mask = [.all]
            case .portrait:
                mask = [.portrait]
            case .portraitUpsideDown:
                mask = [.portraitUpsideDown]
            case .landscapeLeft:
                mask = [.landscapeLeft]
            case .landscapeRight:
                mask = [.landscapeRight]
        }

        OrientationController.lockOrientation(mask)

        UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
    }
}
Run Code Online (Sandbox Code Playgroud)

比,在 AppDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // do stuff
    OrientationController.lockOrientation(.portrait)
    return true
}

// MARK: - Orientation

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return OrientationController.allowedOrientation
}
Run Code Online (Sandbox Code Playgroud)

每当你想改变方向时,请执行以下操作:

OrientationController.forceLockOrientation(.landscapeRight)
Run Code Online (Sandbox Code Playgroud)

注意:有时,设备可能无法通过此类呼叫进行更新,因此您可能需要执行以下操作

OrientationController.forceLockOrientation(.portrait)
OrientationController.forceLockOrientation(.landscapeRight)
Run Code Online (Sandbox Code Playgroud)

就这样


Moj*_*o66 9

这应该从iOS 6开始向上,但我只在iOS 8上测试它.子类UINavigationController并覆盖以下方法:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationLandscapeRight;
}

- (BOOL)shouldAutorotate {
    return NO;
}
Run Code Online (Sandbox Code Playgroud)

或询问可见的视图控制器

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return self.visibleViewController.preferredInterfaceOrientationForPresentation;
}

- (BOOL)shouldAutorotate {
    return self.visibleViewController.shouldAutorotate;
}
Run Code Online (Sandbox Code Playgroud)

并在那里实施方法.


ohh*_*hho 9

这是对Sid Shah的回答中的评论的反馈,关于如何使用以下方法禁用动画:

[UIView setAnimationsEnabled:enabled];
Run Code Online (Sandbox Code Playgroud)

码:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:NO];
    [UIView setAnimationsEnabled:NO];

    // Stackoverflow #26357162 to force orientation
    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:NO];
    [UIView setAnimationsEnabled:YES];
}
Run Code Online (Sandbox Code Playgroud)


Lau*_*Lau 6

如果您使用的是navigationViewController,则应为此创建自己的超类并覆盖:

- (BOOL)shouldAutorotate {
  id currentViewController = self.topViewController;

  if ([currentViewController isKindOfClass:[SecondViewController class]])
    return NO;

  return YES;
}
Run Code Online (Sandbox Code Playgroud)

这将禁用SecondViewController中的旋转,但如果您在设备处于纵向方向时按下SecondViewController,则SecondViewController将以纵向模式显示.

假设您正在使用故事板.您必须在"onClick"方法中创建手动segue(如何):

- (IBAction)onPlayButtonClicked:(UIBarButtonItem *)sender {
  NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
  [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
  [self performSegueWithIdentifier:@"PushPlayerViewController" sender:self];
}
Run Code Online (Sandbox Code Playgroud)

这将在您的超类禁用自动旋转功能之前强制横向方向.


Ali*_*ani 6

Xcode 8方法转换为属性,因此以下工作Swift:

override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.portrait
}

override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return UIInterfaceOrientation.portrait
}

override public var shouldAutorotate: Bool {
    return true
}
Run Code Online (Sandbox Code Playgroud)