iOS 屏幕旋转与系统版本差异说明

4 阅读3分钟

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.swiftat_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 以下
旋转 APIUIWindowScene.requestGeometryUpdateUIDevice.setValue + attemptRotationToDeviceOrientation
push 能否旋转可以,系统会按新 top VC 更新方向难稳定,受询问时机和“当前 VC”判断影响
推荐方式push 即可从竖屏页进横屏登录时,推荐 present 登录 Nav