iOS旋转屏幕设置总结

iOS开发中,经常会碰到某些页面需要支持横屏显示,某些又仅支持竖屏显示,那怎么样才能比较完美的实现各个界面的横竖屏设置,有不相互影响呢?
经过几个项目的实践比较,个人感觉让各个viewController自己来控制自己的横竖屏显示是最好的!!!
问题是怎么设置才最简单方便不容易出错~

注:以下全部是iOS6以后的方法,iOS6之前的太久远了,就不提了;
这里仅涉及设置的方法,具体转屏的方法,有空再写;

首先,要确定APP支持哪些方向

可以通过两种方式来确定:

  1. 在工程设置处勾选


    工程设置

    或者在或者在info.plist中设置


    info.plist中设置

    这两个地方是等价的,改了其中一个地方,另一个也会跟着变;
  2. 在AppDelegate中实现方法
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return .allButUpsideDown
    }

1或者2必须实现至少一个才行;
什么?你说两个都没实现?那系统会按默认的.allButUpsideDown来处理。。。
什么什么?你说两个都实现了设置的值还不一样?那系统会以AppDelegate中实现的代码为准。。。

其次,要确定viewController支持的方向

viewController通过以下方法来确定:

    open override var shouldAutorotate: Bool {
        return false
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
         return .portrait
    }
    
    open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return .portrait
    }

第一个方法确定viewController是否会自动旋转,第二个方法确定viewController支持哪些方向,第三方方法确定viewController弹出来时的方向;
需要注意的是:
这几个方法只有当viewController是window的rootViewController或者viewController是present出来时,才会起作用!
这几个方法只有当viewController是window的rootViewController或者viewController是present出来时,才会起作用!
这几个方法只有当viewController是window的rootViewController或者viewController是present出来时,才会起作用!
重要的事情说三遍

也就是说,如果app是常见的tabBarController+navigationController+viewController的结构的话,rootViewController是tabBarController,
所以只有tabBarController的这三个方法会被调用!
那怎么实现开头说的让各个viewController来控制自己的方向呢?
其实很简单,因为tabBarController和navigationController都是viewController的容器,让他们返回当前显示的viewController的相应方法就行了!
以navigationController为例,就是:

    open override var shouldAutorotate: Bool {
        if let viewController = self.topViewController {
            return viewController.shouldAutorotate
        } else {
            return false
        }
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let viewController = self.topViewController {
            return viewController.supportedInterfaceOrientations
        }  else {
            return .portrait
        }
    }
    
    open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        if let viewController = self.topViewController {
            return viewController.preferredInterfaceOrientationForPresentation
        }  else {
            return .portrait
        }
    }

注意:viewController最终支持的方向是以上app支持方向和viewController支持方向两个规则的交集,如果交集为空,就会crash!!!

基本原理知道了,也该回答最初的问题了,简单方便又不容易出错的设置方法就是

结论:写基类

这里需要至少三个基类,分别继承tabBarController,navigationController和viewController;
在其中分别实现转屏方法,然后项目中所有的其他类,都继承这几个基类;
然后,在需要支持不同方向的viewController中,重载转屏的三个方法,就大功告成了~
例:
这里OJSTabBarController,OJSNavigationController,OJSViewController分别集成自对应的UIViewController

extension OJSTabBarController {
    
    //这里,如果selectedViewController是navigationController,因为navigationController也是返回它的topViewController的状态,所以最终还是各个viewController自己来控制自己的状态
    
    open override var shouldAutorotate: Bool {
        if let tempViewController = self.selectedViewController {
            return tempViewController.shouldAutorotate
        } else {
            return false
        }
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let tempViewController = self.selectedViewController {
            return tempViewController.supportedInterfaceOrientations
        } else {
            return UIInterfaceOrientationMask.portrait
        }
    }
    
    
    open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        if let tempViewController = self.selectedViewController {
            return tempViewController.preferredInterfaceOrientationForPresentation
        } else {
            return UIInterfaceOrientation.portrait
        }
    }
}

extension OJSNavigationController {
    //这里只需要返回self.topViewController的相应属性,让各个viewController自己控制就行了
    //present出来的viewController本来就是受自己控制,跟nav无关
    
    open override var shouldAutorotate: Bool {
        if let viewController = self.topViewController {
            return viewController.shouldAutorotate
        } else {
            return false
        }
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let viewController = self.topViewController {
            return viewController.supportedInterfaceOrientations
        }  else {
            return .portrait
        }
    }
    
    
    open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        if let viewController = self.topViewController {
            return viewController.preferredInterfaceOrientationForPresentation
        }  else {
            return .portrait
        }
    }
}



extension OJSViewController {
    
    open override var shouldAutorotate: Bool {
        return false
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
         return .portrait
    }
    
    open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return .portrait
    }
}

这样做的好处是:
每个viewController都有默认的转屏设置,不会因为漏写了代码而出现不应该出现的旋转;
每个viewController是自己控制自己的方向,不会对前后viewController有任何影响
需要特殊方向的viewController,仅实现自己的方法就行,不用再在rootViewController中做一大堆判断;
。。。。。。

彩蛋

之前提交appstore时遇到个极其奇葩的问题,苹果审核人员用iPad装我们的iPhone app,然后发现他的iPad横着启动app时界面全乱了,
然后他就截了个图,把我们的app拒掉了。。。。。。
当时我的内心真是极其崩溃的,,,iPad竖着启动app时,就一切正常,横着启动app时,界面就乱套了。。。
这想想应该是苹果的锅啊!!!
后来偶然发现个非常规的解决方法:
在工程设置处设置app只支持portrait,然后在AppDelegate中设置为支持其他;这样app启动的时候就会强制用竖屏方式启动,
iPad上的问题就解决了。。。苹果也给审核通过了。。。

有什么问题,欢迎讨论~

你可能感兴趣的:(iOS旋转屏幕设置总结)