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
相关产品推荐
相关产品推荐

