iOS 16 屏幕旋转新方法
时间: 2025-11-30 19:43:36
(部分内容来自网络,其真实性存疑,为了避免对您造成误导,请谨慎甄别。)
🍎 iOS 16 屏幕旋转新方法
在 iOS 16 中,Apple 引入了新的 API 来替代 attemptRotationToDeviceOrientation() 和直接设置 UIDevice.orientation 的方式。
核心新 API 是:
- setNeedsUpdateOfSupportedInterfaceOrientations():这是 UIViewController 的实例方法,用于通知系统该视图控制器支持的方向已改变,应触发方向更新。这通常与你视图控制器的 supportedInterfaceOrientations 属性重写配合使用。
- UIWindowScene.requestGeometryUpdate(_:):当你需要强制设备旋转到特定方向时,应使用此方法。它接受一个 UIWindowSceneGeometryPreferences 对象(具体来说,在 iOS 上通常是 UIWindowSceneGeometryPreferencesIOS)来指定期望的方向。
下面的表格对比了新旧 API 的使用场景和方法:
| 使用场景 | 旧方法 (iOS 16 前) | 新方法 (iOS 16 及以上) |
|---|---|---|
| 通知系统方向需更新 | UIViewController.attemptRotationToDeviceOrientation() | yourViewController.setNeedsUpdateOfSupportedInterfaceOrientations() |
| 强制设备旋转 | KVC设置 UIDevice.orientation | UIWindowScene.requestGeometryUpdate(_:) |
🛠️ 新API代码示例
这里是如何在你的扫雷游戏中应用新 API 的示例。
1. 在 AppDelegate 中设置全局方向控制
这个基础部分和之前类似,确保 AppDelegate 中存在 orientationLock 属性并在对应方法中返回它。
class AppDelegate: NSObject, UIApplicationDelegate {
// 定义一个全局变量来控制方向锁
static var orientationLock: UIInterfaceOrientationMask = .portrait {
didSet {
// 当方向锁改变时,通知所有视图控制器更新方向
UIViewController.attemptRotationToDeviceOrientation()
}
}
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return AppDelegate.orientationLock
}
}2. 在特定视图控制器(如你的 MinesweeperView)中控制方向
在你的 MinesweeperView 对应的 UIViewController 中,重写方向相关属性,并在适当的时候(如视图出现/消失时)更新全局方向锁并调用新 API。
// 假设这是你的 MinesweeperView 所在的 ViewController
class GameViewController: UIViewController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
// 定义此控制器支持的方向
return .all // 或者 [.portrait, .landscapeLeft, .landscapeRight]
}
override func viewDidLoad() {
super.viewDidLoad()
// 设置内容视图,例如你的 SwiftUI MinesweeperView
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// 进入游戏时,解锁方向或设置为所有方向
AppDelegate.orientationLock = .all
// 🆕 关键:通知系统需要更新支持的方向
if #available(iOS 16.0, *) {
self.setNeedsUpdateOfSupportedInterfaceOrientations()
} else {
// 对于 iOS 16 以下,仍使用旧方法(但你的项目目标可能已经不需要了)
UIViewController.attemptRotationToDeviceOrientation()
}
// 🆕 可选:如果你希望一进入此页面就强制横屏,可以使用更强力的方法
forceLandscapeIfNeeded()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// 离开游戏时,恢复竖屏锁定
AppDelegate.orientationLock = .portrait
// 🆕 通知系统更新
if #available(iOS 16.0, *) {
self.setNeedsUpdateOfSupportedInterfaceOrientations()
} else {
UIViewController.attemptRotationToDeviceOrientation()
}
}
// 🆕 强制横屏的方法(使用 iOS 16 新 API)
private func forceLandscapeIfNeeded() {
guard #available(iOS 16.0, *) else { return }
// 获取当前的 window scene
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return }
// 创建横屏偏好设置
let geometryPreferences = UIWindowSceneGeometryPreferencesIOS(interfaceOrientations: .landscape)
// 请求更新几何结构(即旋转屏幕)
windowScene.requestGeometryUpdate(geometryPreferences) { error in
print("强制横屏请求完成,错误: $String(describing: error))")
}
}
}3. 在 SwiftUI 中集成
由于你的 MinesweeperView 是 SwiftUI 视图,你需要通过 UIViewControllerRepresentable 将其包装,或者在 SwiftUI 的生命周期事件中调用上述逻辑。一个更SwiftUI的方式是使用自定义修饰符或 onAppear 来触发方向变化。
// 在 MinesweeperView 的 body 中或 .onAppear 修饰符里
struct MinesweeperView: View {
var body: some View {
// ... 你的扫雷游戏UI
.onAppear {
// 通知需要更新方向
if #available(iOS 16.0, *) {
// 可能需要获取当前的 UIViewController
// 一种常见做法是通过 Notification 或 Environment 将请求传递到 UIKit 层
// 这里简单示意:假设你有一个方法来处理方向改变
AppDelegate.orientationLock = .all
// 调用一个全局函数来触发 setNeedsUpdate...
triggerOrientationUpdate()
}
}
.onDisappear {
AppDelegate.orientationLock = .portrait
triggerOrientationUpdate()
}
}
}
// 需要一个方法来找到当前最顶层的 ViewController 并调用 setNeedsUpdate...
// 这部分代码通常放在你的 AppDelegate 或一个全局工具类中
func triggerOrientationUpdate() {
if #available(iOS 16.0, *) {
// 找到当前活跃的窗口场景和视图控制器
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let rootVC = windowScene.windows.first(where: { $0.isKeyWindow })?.rootViewController else { return }
// 递归找到当前呈现的视图控制器
func findTopViewController(from vc: UIViewController?) -> UIViewController? {
if let nav = vc as? UINavigationController {
return findTopViewController(from: nav.visibleViewController)
} else if let tab = vc as? UITabBarController, let selected = tab.selectedViewController {
return findTopViewController(from: selected)
} else if let presented = vc?.presentedViewController {
return findTopViewController(from: presented)
}
return vc
}
if let topVC = findTopViewController(from: rootVC) {
topVC.setNeedsUpdateOfSupportedInterfaceOrientations()
}
} else {
UIViewController.attemptRotationToDeviceOrientation()
}
}希望这些新的 API 和示例代码能帮你解决问题!如果还有不清楚的地方,请随时提问。