如何在 iOS 8 中强制视图控制器方向?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26357162/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:11:34  来源:igfitidea点击:

How to force view controller orientation in iOS 8?

iosobjective-cios8uinavigationcontrollerautorotate

提问by Rashmi Ranjan mallick

Before iOS 8, we used below code in conjunction with supportedInterfaceOrientationsand shouldAutoRotatedelegate methods to force app orientation to any particular orientation. I used below code snippet to programmatically rotate the app to desired orientation. Firstly, I am changing the status bar orientation. And then just presenting and immediately dismissing a modal view rotates the view to desired orientation.

在 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];

But this is failing in iOS 8. Also, I have seen some answers in stack overflow where people suggested that we should always avoid this approach from iOS 8 onwards.

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

To be more specific, my application is a universal type of application. There are three controllers in total.

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

  1. First View controller- It should support all orientations in iPad and only portrait (home button down) in iPhone.

  2. Second View controller- It should support only landscape right in all conditions

  3. Third View controller- It should support only landscape right in all conditions

  1. 第一个视图控制器- 它应该支持 iPad 中的所有方向,并且只支持 iPhone 中的纵向(主页按钮向下)。

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

  3. 第三个视图控制器- 它应该在所有条件下都只支持横向

We are using navigation controller for page navigation. From the first view controller, on a button click action, we are pushing the second one on stack. So, when the second view controller arrives, irrespective of device orientation, the app should lock in landscape right only.

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

Below is my shouldAutorotateand supportedInterfaceOrientationsmethods in second and third view controller.

下面是第二个和第三个视图控制器中的myshouldAutorotatesupportedInterfaceOrientations方法。

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

Is there any solution for this or any better way of locking a view controller in particular orientation for iOS 8. Please help!!

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

回答by Sunny Shah

For iOS 7 - 10:

对于 iOS 7 - 10:

Objective-C:

目标-C:

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];
[UINavigationController attemptRotationToDeviceOrientation];

Swift 3:

斯威夫特 3:

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()

Just call it in - viewDidAppear:of the presented view controller.

只需- viewDidAppear:在呈现的视图控制器中调用它。

回答by Korey Hinton

Orientation rotation is a little more complicated if you are inside a UINavigationControlleror UITabBarController. The problem is that if a view controller is embedded in one of these controllers the navigation or tab bar controller takes precedence and makes the decisions on autorotation and supported orientations.

如果您在 aUINavigationController或 中,方向旋转会稍微复杂一些UITabBarController。问题是,如果视图控制器嵌入在这些控制器之一中,则导航或标签栏控制器优先,并就自动旋转和支持的方向做出决定。

I use the following 2 extensions on UINavigationController and UITabBarController so that view controllers that are embedded in one of these controllers get to make the decisions.

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

Give View Controllers the Power!

赋予视图控制器权力!

Swift 2.3

斯威夫特 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()
    }
}

Swift 3

斯威夫特 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
    }
}

Now you can override the supportedInterfaceOrientationsmethod or you can override shouldAutoRotatein the view controller you want to lock down otherwise you can leave out the overrides in other view controllers that you want to inherit the default orientation behavior specified in your app's plist

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

Disable Rotation

禁用旋转

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

Lock to Specific Orientation

锁定特定方向

class ViewController: UIViewController {
    override func supportedInterfaceOrientations() -> Int {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
}

In theory this should work for all complex view controller hierarchies, but I have noticed an issue with UITabBarController. For some reason it wants to use a default orientation value. See the following blog post if you are interested in learning about how to work around some of the issues:

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

Lock Screen Rotation

锁屏旋转

回答by Vincil Bishop

This is what worked for me:

这对我有用:

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

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

Call it in your viewDidAppear: method.

在您的 viewDidAppear: 方法中调用它。

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

    [UIViewController attemptRotationToDeviceOrientation];
}

回答by Zipme

I found that if it's a presented view controller, you can override preferredInterfaceOrientationForPresentation

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

Swift:

迅速:

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

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

override func shouldAutorotate() -> Bool {
  return false
}

回答by Alessandro Ornano

This way work for me in Swift 2iOS 8.x:

这种方式在Swift 2iOS 8.x 中对我有用:

PS (this method dont require to override orientation functions like shouldautorotate on every viewController, just one method on AppDelegate)

PS(此方法不需要在每个视图控制器上覆盖诸如 shouldautorotate 之类的方向功能,只是 AppDelegate 上的一个方法)

Check the "requires full screen" in you project general info. enter image description here

检查项目一般信息中的“需要全屏”。 在此处输入图片说明

So, on AppDelegate.swift make a variable:

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

var enableAllOrientation = false

So, put also this func:

所以,也把这个功能:

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

So, in every class in your project you can set this var in viewWillAppear:

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

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

If you need to make a choices based on the device type you can do this:

如果您需要根据设备类型做出选择,您可以这样做:

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
        }
    }

回答by gbk

First of all - this is a bad idea, in general, something wrong going with your app architecture, but, sh..t happens, if so, you can try to make something like below:

首先 - 这是一个坏主意,一般来说,您的应用程序架构有问题,但是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")
    }
}

Than, in AppDelegate

比,在 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
}

And whenever you want to change orientation do as:

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

OrientationController.forceLockOrientation(.landscapeRight)

Note: Sometimes, device may not update from such call, so you may need to do as follow

注意:有时,设备可能不会从此类调用中更新,因此您可能需要执行以下操作

OrientationController.forceLockOrientation(.portrait)
OrientationController.forceLockOrientation(.landscapeRight)

That's all

就这样

回答by ohho

This is a feedback to comments in Sid Shah's answer, regarding how to disable animations using:

这是对Sid Shah 回答中关于如何禁用动画的评论的反馈:

[UIView setAnimationsEnabled:enabled];

Code:

代码:

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

回答by Mojo66

This should work from iOS 6 on upwards, but I've only tested it on iOS 8. Subclass UINavigationControllerand override the following methods:

这应该适用于 iOS 6 以上,但我只在 iOS 8 上测试过它。子类UINavigationController并覆盖以下方法:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationLandscapeRight;
}

- (BOOL)shouldAutorotate {
    return NO;
}

Or ask the visible view controller

或者询问可见视图控制器

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

- (BOOL)shouldAutorotate {
    return self.visibleViewController.shouldAutorotate;
}

and implement the methods there.

并在那里实现方法。

回答by Lau

If you are using navigationViewController you should create your own superclass for this and override:

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

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

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

  return YES;
}

this will disable rotation in SecondViewControllerbut if you push your SecondViewControllerwhen your device is on portrait orientation then your SecondViewControllerwill appear in portrait mode.

这将禁用SecondViewController 中的旋转,但是如果您在设备处于纵向时按下SecondViewController,那么您的SecondViewController将显示为纵向模式。

Assume that you are using storyboard. You have to create manual segue (How to) and in your "onClick" method:

假设您正在使用故事板。您必须创建手动转场(How to)并在您的“onClick”方法中:

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

This will force landscape orientation before your superclass disable autorotate feature.

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

回答by Ali Momen Sani

On Xcode 8the methods are converted to properties, so the following works with Swift:

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
}