iOS 16应用手动启动时自动旋转失效问题求助
iOS 16 应用手动启动时自动旋转失效问题
问题详情
- 仅iOS 16存在该异常,其他iOS版本正常
- 手动点击应用图标启动:自动旋转逻辑完全失效,
viewWillTransition(to:with:)未触发,子视图不旋转 - Xcode调试启动:旋转逻辑正常执行
- 核心实现逻辑:
- 启动时通过重写
supportedInterfaceOrientations返回.landscapeRight锁定旋转 - 延迟后修改状态解锁旋转,并调用
setNeedsUpdateOfSupportedInterfaceOrientations(iOS 16)或attemptRotationToDeviceOrientation(旧版本)强制旋转到当前设备方向
- 启动时通过重写
- 已尝试将触发代码移至
viewDidAppear,问题仍未解决
复现代码(初始版本)
import UIKit class ViewController: UIViewController { public var windowOrientation: UIInterfaceOrientation { return view.window?.windowScene?.interfaceOrientation ?? .unknown } private var disableAutoRotation = true override var supportedInterfaceOrientations: UIInterfaceOrientationMask { var orientations: UIInterfaceOrientationMask = .landscapeRight if !self.disableAutoRotation { orientations = .all } return orientations } override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.systemGreen DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: { self.autoRotateNotification() }) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: {_ in }, completion: { [unowned self] _ in let orient = self.windowOrientation self.view.backgroundColor = orient.isLandscape ? .systemGreen : .systemOrange }) } func autoRotateNotification() { DispatchQueue.main.asyncAfter(deadline: .now(), execute: { self.disableAutoRotation = false if #available(iOS 16.0, *) { UIView.performWithoutAnimation { self.setNeedsUpdateOfSupportedInterfaceOrientations() } } else { UIViewController.attemptRotationToDeviceOrientation() } }) } }
补充复现代码(移至viewDidAppear版本)
import UIKit class ViewController: UIViewController { public var windowOrientation: UIInterfaceOrientation { return view.window?.windowScene?.interfaceOrientation ?? .unknown } private var disableAutoRotation = true private var autoRotated = false override var supportedInterfaceOrientations: UIInterfaceOrientationMask { var orientations: UIInterfaceOrientationMask = .landscapeRight if !self.disableAutoRotation { orientations = .all } return orientations } override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return .landscapeLeft } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if !autoRotated { autoRotated = true self.autoRotateNotification() } } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: {_ in }, completion: { [unowned self] _ in let orient = self.windowOrientation self.view.backgroundColor = orient.isLandscape ? .systemGreen : .systemOrange }) } func autoRotateNotification() { self.disableAutoRotation = false if #available(iOS 16.0, *) { self.setNeedsUpdateOfSupportedInterfaceOrientations() } else { UIViewController.attemptRotationToDeviceOrientation() } } }
解决办法
1. 适配iOS 16新的旋转API
iOS 16中系统对窗口场景的旋转控制逻辑有调整,仅调用setNeedsUpdateOfSupportedInterfaceOrientations可能无法触发旋转,需结合UIWindowScene的requestGeometryUpdate(_:)方法主动请求旋转更新:
func autoRotateNotification() { self.disableAutoRotation = false self.setNeedsUpdateOfSupportedInterfaceOrientations() if #available(iOS 16.0, *) { guard let windowScene = view.window?.windowScene else { return } windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: .all)) { error in if let error = error { print("旋转请求失败: \(error.localizedDescription)") } } } else { UIViewController.attemptRotationToDeviceOrientation() } }
2. 确保在窗口场景激活后触发旋转
手动启动时,应用启动阶段窗口场景可能未完全激活,导致旋转请求无效。可通过监听UIScene.didActivateNotification,在场景激活后再执行旋转逻辑:
override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.systemGreen NotificationCenter.default.addObserver(self, selector: #selector(onSceneActivated), name: UIScene.didActivateNotification, object: nil) } @objc private func onSceneActivated() { DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in self?.autoRotateNotification() NotificationCenter.default.removeObserver(self!) } } deinit { NotificationCenter.default.removeObserver(self) }
3. 检查Info.plist配置
确保Info.plist中的UISupportedInterfaceOrientations包含所有需要支持的方向,iOS 16会严格校验该配置:
<key>UISupportedInterfaceOrientations</key> <array> <string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> </array>
说明
以上方案针对iOS 16的旋转逻辑调整,解决手动启动与调试启动的行为差异问题,核心是确保旋转请求在窗口场景完全就绪后发出,并使用iOS 16专属API主动触发旋转更新。
内容的提问来源于stack exchange,提问作者Deepak Sharma
相关产品推荐
相关产品推荐

