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

iOS16中SwiftUI界面横竖屏旋转适配问题(原iOS15方案失效)

解决方案:iOS16+ SwiftUI视图动态控制屏幕旋转

核心思路

通过自定义UIHostingController子类封装旋转控制逻辑,配合SwiftUI修饰符快速接入,同时保留AppDelegate的全局方向锁机制,确保导航离开目标视图后自动恢复竖屏。

步骤1:更新AppDelegate的方向控制逻辑

保留原有的全局方向锁变量,重写方向支持方法适配iOS16:

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    static var orientationLock = UIInterfaceOrientationMask.portrait

    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return AppDelegate.orientationLock
    }
}

步骤2:自定义支持旋转的UIHostingController子类

创建RotatableHostingController,负责在视图生命周期中切换方向锁并请求场景更新:

import SwiftUI

class RotatableHostingController<Content: View>: UIHostingController<Content> {
    private let supportedOrientations: UIInterfaceOrientationMask
    private let originalOrientationLock: UIInterfaceOrientationMask

    init(rootView: Content, supportedOrientations: UIInterfaceOrientationMask) {
        self.supportedOrientations = supportedOrientations
        self.originalOrientationLock = AppDelegate.orientationLock
        super.init(rootView: rootView)
    }

    @MainActor required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        AppDelegate.orientationLock = supportedOrientations
        if let windowScene = view.window?.windowScene {
            windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: supportedOrientations))
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        AppDelegate.orientationLock = originalOrientationLock
        if let windowScene = view.window?.windowScene {
            windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: originalOrientationLock))
        }
    }
}

步骤3:创建SwiftUI修饰符简化调用

自定义修饰符,让目标视图快速绑定旋转逻辑:

extension View {
    func supportedOrientations(_ orientations: UIInterfaceOrientationMask) -> some View {
        self.background(
            UIViewControllerAdaptor {
                RotatableHostingController(rootView: self, supportedOrientations: orientations)
            }
        )
    }
}

// 辅助结构体,用于将自定义UIHostingController嵌入SwiftUI
struct UIViewControllerAdaptor<VC: UIViewController>: UIViewControllerRepresentable {
    let makeVC: () -> VC

    func makeUIViewController(context: Context) -> VC {
        makeVC()
    }

    func updateUIViewController(_ uiViewController: VC, context: Context) {}
}

步骤4:在目标SwiftUI视图中使用

直接给需要旋转的视图添加修饰符,导航离开时自动恢复竖屏:

struct LandscapeEnabledView: View {
    var body: some View {
        Text("支持竖屏和左横屏")
            .supportedOrientations([.portrait, .landscapeLeft])
    }
}

关键注意事项

  • 根控制器保持普通UIHostingController,仅给需要旋转的视图用自定义控制器包装
  • 必须在viewWillAppear/viewWillDisappear中处理旋转逻辑,SwiftUI的onAppear/onDisappear时机可能滞后
  • 请求场景更新时,使用当前视图所在的windowScene,而非全局取第一个场景,避免多场景适配问题

内容的提问来源于stack exchange,提问作者NNN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 15:05:14