iOS 屏幕旋转与系统版本差异说明
本文档说明:从竖屏页(HHWebViewVC)跳转到横屏页(登录)时,为何 iOS 16 及以上用 push 即可旋转,而 iOS 16 以下采用 present 方案更稳妥。
一、iOS 16 及以上:为什么 push 就能旋转?
1. 旋转 API 不同
- iOS 16+:使用
UIWindowScene.requestGeometryUpdate(_:errorHandler:)(配合UIWindowSceneGeometryPreferencesIOS)来请求界面几何变化。 - 该 API 是基于 WindowScene 的,会结合当前窗口上正在展示的视图控制器的
supportedInterfaceOrientations等能力做决策。 - 当 push 到新 VC 后,系统会及时以新的 topViewController 为准更新允许的方向,因此仅靠 push + 新 VC 声明横屏,就足以触发旋转。
2. 项目中的实现
在 UIDevice+Extension.swift 的 at_forceOrientation(to:) 中,iOS 16+ 分支会:
- 取当前
UIWindowScene - 构造几何偏好并调用
requestGeometryUpdate - 调用
setNeedsUpdateOfSupportedInterfaceOrientations()让系统重新询问支持的方向
因此:push 到横屏的登录页后,系统会按新 VC 的方向更新界面,push 即可实现旋转。
二、iOS 16 以下:是否一定要 present 才能旋转?
1. 结论:不是“必须”,但 present 最稳妥
理论上不一定要用 present,但受旧 API 行为限制,用 push 在 iOS 16 以下很难稳定地实现「从竖屏页 push 到横屏页并立刻旋转」。
2. 旧系统的旋转机制(iOS 16 以下)
- 使用
UIDevice.current.setValue(orientation, forKey: "orientation")+UIViewController.attemptRotationToDeviceOrientation()。 - 系统会询问
application(_:supportedInterfaceOrientationsFor:),根据其返回值决定当前 window 允许的方向。 - 关键点:在 push 动画进行中或刚完成时,系统在部分时机下仍可能以上一个 VC(例如竖屏的 HHWebViewVC)作为“当前” VC 来询问,因此会得到 竖屏 的 mask。
- 一旦 AppDelegate 在这一刻返回了竖屏,当前 window 只允许竖屏,之后再调用
setValue(_:forKey: "orientation")和attemptRotationToDeviceOrientation()也不会触发旋转,因为与当前允许方向不一致。
3. 若坚持用 push,理论上可以怎么做?
- 在 push 之前 就通过某种方式让
supportedInterfaceOrientationsFor在“下一帧”开始就返回横屏(例如用全局标志位),这样在 push 后系统询问时能得到横屏。 - 或在 新 VC 的 viewWillAppear / viewDidAppear 里再调一次强制横屏,并配合延迟(如
DispatchQueue.main.async或短 delay),希望那时“当前” VC 已变为新 VC,从而允许横屏。
但存在这些问题:
- 时机依赖:不同设备、不同动画时长下,系统询问的时机不稳定。
- 容易和转场动画、布局时机耦合,表现不一致,难以在所有 iOS 15 及以下机型上复现一致效果。
所以:在 iOS 16 以下,用 push 做“从竖屏到横屏”的旋转,不是完全不可能,但实现脆弱,不推荐作为主方案。
4. 为什么 present 能稳定解决?
- Present 出来的是一套新的呈现层级(例如带导航的 modal)。
- 该 modal 的 rootViewController(如登录 VC)声明横屏,系统会以这一层的 VC 来询问/应用方向,不再受后面被盖住的竖屏 VC 影响。
- 因此从竖屏页 present 一个横屏的登录 Nav,无需和 push 的转场时机博弈,旋转行为清晰、可预期。
所以在工程上:iOS 16 以下从竖屏页进横屏登录,用 present 是最稳妥、可维护的方案。
三、总结对照
| 项目 | iOS 16 及以上 | iOS 16 以下 |
|---|---|---|
| 旋转 API | UIWindowScene.requestGeometryUpdate | UIDevice.setValue + attemptRotationToDeviceOrientation |
| push 能否旋转 | 可以,系统会按新 top VC 更新方向 | 难稳定,受询问时机和“当前 VC”判断影响 |
| 推荐方式 | push 即可 | 从竖屏页进横屏登录时,推荐 present 登录 Nav |