You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 16应用手动启动时自动旋转失效问题求助

iOS 16 应用手动启动时自动旋转失效问题

问题详情

  • 仅iOS 16存在该异常,其他iOS版本正常
  • 手动点击应用图标启动:自动旋转逻辑完全失效,viewWillTransition(to:with:)未触发,子视图不旋转
  • Xcode调试启动:旋转逻辑正常执行
  • 核心实现逻辑:
    1. 启动时通过重写supportedInterfaceOrientations返回.landscapeRight锁定旋转
    2. 延迟后修改状态解锁旋转,并调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 08:10:32