本文屏幕旋转方案仅限于兼容iOS8+
1. 从APP层次谈起 APP常见的布局层次如下图所示: 当工程目标开启了多个屏幕方向之后,具体类中有关屏幕旋转的配置其实只与当前屏幕展示模块的最外层VC容器有关。 但由于往往存在容器中某些VC针对屏幕旋转的个性化配置,所以需要进行从里层VC到外层容器的旋转状态传递。例如:
1 2 3 4 5 6 7 8 9 10 11 override func shouldAutorotate () -> Bool { return true } override func supportedInterfaceOrientations () -> UIInterfaceOrientationMask { return .Portrait } override func preferredInterfaceOrientationForPresentation () -> UIInterfaceOrientation { return .Portrait }
自定义UINavigationController的配置
1 2 3 4 5 6 7 8 9 10 11 override public func shouldAutorotate () -> Bool { return self .viewControllers.last?.shouldAutorotate() ?? false } override public func supportedInterfaceOrientations () -> UIInterfaceOrientationMask { return self .viewControllers.last?.supportedInterfaceOrientations() ?? .Portrait } override public func preferredInterfaceOrientationForPresentation () -> UIInterfaceOrientation { return self .viewControllers.last?.preferredInterfaceOrientationForPresentation() ?? .Portrait }
1 2 3 4 5 6 7 8 9 10 11 override func shouldAutorotate () -> Bool { return self .selectedViewController?.shouldAutorotate() ?? false } override func supportedInterfaceOrientations () -> UIInterfaceOrientationMask { return self .selectedViewController?.supportedInterfaceOrientations() ?? .Portrait } override func preferredInterfaceOrientationForPresentation () -> UIInterfaceOrientation { return self .selectedViewController?.preferredInterfaceOrientationForPresentation() ?? .Portrait }
2. AppDelegate配置 按照上面的方法配置好后,就可以自由的控制转屏了,但在某些情况下会存在问题,举个例子:假如A页面屏幕锁定为竖屏,点击A页面的一个按钮跳转到了B页面(方式存在push跟present两种),B页面是可以进行横竖屏旋转的,当B页面旋转至横屏,这时候点击返回,会发现A页面也变成横屏展示了,而且无法通过屏幕旋转恢复到竖屏展示。这时候下面这个代理方法就排上用场了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func application (application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask { if self .window?.rootViewController?.presentedViewController != nil { return .Portrait } let baseTabBarController = self .window?.rootViewController as ? BaseTabBarController if ((baseTabBarController?.selectedViewController as ? BaseNavigationController )?.topViewController is RotateDetailViewController { return .AllButUpsideDown } else { return .Portrait } }
3. 强制旋屏
前提条件:该VC允许旋转
1 2 3 4 5 6 7 8 9 10 11 func forcePortrait () { let width = UIScreen .mainScreen().bounds.size.width let height = UIScreen .mainScreen().bounds.size.height let isLandscape = width > height if isLandscape { let device = UIDevice .currentDevice() let number = NSNumber (integer: UIInterfaceOrientation .Portrait .rawValue) device.setValue(number, forKey: "orientation" ) } }
1 2 3 4 5 6 7 8 9 10 11 func forceLandScape () { let width = UIScreen .mainScreen().bounds.size.width let height = UIScreen .mainScreen().bounds.size.height let isLandscape = width < height if isLandscape { let device = UIDevice .currentDevice() let number = NSNumber (integer: UIInterfaceOrientation .LandscapeRight .rawValue) device.setValue(number, forKey: "orientation" ) } }
总结 以上方案基本可以搞定大部分的屏幕旋转场景了。如果APP的产品需求中主体为固定方向,只要求对弹出(present)模态视图进行旋转的话,可以参考下面这篇文章:iOS Orientations: Landscape orientation for only one View Controller 这么做会更加方便一些,但问题是这种方案对于push模式的场景并不适用,需要结合以上方案综合解决。