How to force view controller orientation in iOS 8?

前端 未结 25 2087
太阳男子
太阳男子 2020-11-22 13:11

Before iOS 8, we used below code in conjunction with supportedInterfaceOrientations and shouldAutoRotate delegate methods to force app orie

相关标签:
25条回答
  • 2020-11-22 13:20

    For me, the top level VC needed to implement the orientation overrides. Using VC's down the stack will have no effect if the top VC is not implementing.

    VC-main
        |
        -> VC 2
            |
            -> VC 3
    

    Only VC-Main is listened to, essentially in my testing.

    0 讨论(0)
  • 2020-11-22 13:21

    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:

    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

    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

    0 讨论(0)
  • 2020-11-22 13:22

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

    [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];
    }
    
    0 讨论(0)
  • 2020-11-22 13:23

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

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

    Check the "requires full screen" in you project general info.

    So, on AppDelegate.swift make a variable:

    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:

    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
            }
        }
    
    0 讨论(0)
  • 2020-11-22 13:24

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

    - (BOOL)shouldAutorotate {
      id currentViewController = self.topViewController;
    
      if ([currentViewController isKindOfClass:[SecondViewController class]])
        return NO;
    
      return YES;
    }
    

    this will disable rotation in SecondViewController but if you push your SecondViewController when your device is on portrait orientation then your SecondViewController will appear in portrait mode.

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

    - (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.

    0 讨论(0)
  • 2020-11-22 13:24

    My solution

    In AppDelegate:

    func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
        if let topController = UIViewController.topMostViewController() {
            if topController is XXViewController {
                return [.Portrait, .LandscapeLeft]
            }
        }
        return [.Portrait]
    }
    

    XXViewController is the ViewController you want to support Landscape mode.

    Then Sunny Shah's solution would work in your XXViewController on any iOS version:

    let value = UIInterfaceOrientation.LandscapeLeft.rawValue
    UIDevice.currentDevice().setValue(value, forKey: "orientation")
    

    This is the utility function to find the top most ViewController.

    extension UIViewController {
    
        /// Returns the current application's top most view controller.
        public class func topMostViewController() -> UIViewController? {
            let rootViewController = UIApplication.sharedApplication().windows.first?.rootViewController
            return self.topMostViewControllerOfViewController(rootViewController)
        }
    
    
    
        /// Returns the top most view controller from given view controller's stack.
        class func topMostViewControllerOfViewController(viewController: UIViewController?) -> UIViewController? {
            // UITabBarController
            if let tabBarController = viewController as? UITabBarController,
               let selectedViewController = tabBarController.selectedViewController {
                return self.topMostViewControllerOfViewController(selectedViewController)
            }
    
            // UINavigationController
            if let navigationController = viewController as? UINavigationController,
               let visibleViewController = navigationController.visibleViewController {
                return self.topMostViewControllerOfViewController(visibleViewController)
            }
    
            // presented view controller
            if let presentedViewController = viewController?.presentedViewController {
                return self.topMostViewControllerOfViewController(presentedViewController)
            }
    
            // child view controller
            for subview in viewController?.view?.subviews ?? [] {
                if let childViewController = subview.nextResponder() as? UIViewController {
                    return self.topMostViewControllerOfViewController(childViewController)
                }
            }
    
            return viewController
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题