使用Auto Layout
来进行布局就不用自己去监听横竖屏事件了,只需要绘制多套布局即可。但是项目有很多页面是自己手动计算的,于是只有想办法再旋转屏幕时重新布局。
相关枚举
屏幕方向有3个相关枚举,界面方向UIInterfaceOrientation
,设备方向UIDeviceOrientation
,支持旋转方向UIInterfaceOrientationMask
。
注意UIInterfaceOrientation与UIDeviceOrientation左右方向是相反的
1 | typedef NS_ENUM(NSInteger, UIInterfaceOrientation) { |
横竖屏控制
控制界面横竖屏切换有3个重要的点,最终结果以这三个地方的值取交集。
1.info.plist全局控制
可以在General->Deplyment Info
界面上勾选
info.plist文件中配置也是一样的,两边会同步变更
2.AppDelegate中根据不同Window控制
1 | // AppDelegate |
3.在ViewController中控制当前页面
1 | // UIViewController |
需要注意的是,交集不能为空,否则会导致crash
*** Terminating app due to uncaught exception ‘UIApplicationInvalidInterfaceOrientation’, reason: ‘Supported orientations has no common orientation with the application, and [ViewController
shouldAutorotate] is returning YES’
旋转事件监听
旋转事件传递过程
1 | op0=>operation: __CFRunLoopDoSources0 |
屏幕旋转相关事件
viewWillTransitionToSize:withTransitionCoordinator:
- ViewController被父容器变更size时调用(例如window旋转时调用root view controller的该方法)
- 如果重载该方法,需要调用super传递事件给子ViewController
- 这个方法是最关键的,可以在该方法中对界面进行重新布局
1 | - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator |
UIApplicationWillChangeStatusBarOrientationNotification
- 状态栏将要旋转,这个时候取view的frame还是旋转之前的
- NSNotification中用key
UIApplicationStatusBarOrientationUserInfoKey
可以取到将要旋转到的方向。
UIApplicationDidChangeStatusBarOrientationNotification
- 状态栏已经旋转,这个时候取view的frame是旋转之后的
- NSNotification中用key
UIApplicationStatusBarOrientationUserInfoKey
可以取到旋转之前的方向。
UIDeviceOrientationDidChangeNotification
- 设备方向变更,在收到通知时取view的frame是旋转之后的。
- 在手机上将旋转屏幕锁定之后,设备方向变更之后收不到该通知
- 在代码里面限制设备旋转方向,设备方向变更后依然能收到该通知
调用顺序如下
1 | st=>start: 旋转屏幕 |
自定义Window的旋转事件
如果想要在自定义Window的子View收到屏幕旋转通知,要设置UIWindow的rootViewController,然后把所有子view都加到rootViewController,系统会处理横竖屏事件。这里我还遇到一个坑记一个实现UIWindow子类的小坑。
推荐阅读
https://satanwoo.github.io/2016/09/17/uiwindow-iOS/
iOS屏幕旋转知识点以及实现
iOS 屏幕旋转的那些事(一)
浅谈iOS的多Window处理