如何在SwiftUI的SpriteView中禁用SKView自动旋转并获取真实方向
解决方案:在SwiftUI+SpriteView中完全禁用自动旋转并读取真实设备方向
一、完全阻止自动旋转(避免先转再纠正)
iOS的屏幕旋转权限由当前活跃的UIViewController管控,而非SKView或SpriteView本身。因此要从根源阻止旋转,需要自定义承载SKView的UIViewController,并在其中限制旋转规则,再包装为SwiftUI可用的View。
步骤1:自定义承载SKView的ViewController
import UIKit import SpriteKit class LockedPortraitSKViewController: UIViewController { var scene: SKScene? override func viewDidLoad() { super.viewDidLoad() guard let scene = scene else { return } // 配置SKView let skView = view as! SKView skView.showsFPS = true skView.showsNodeCount = true skView.ignoresSiblingOrder = true scene.scaleMode = .resizeFill skView.presentScene(scene) } // 限制仅支持竖屏 override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } // 禁止自动旋转 override var shouldAutorotate: Bool { return false } // 可选:锁定状态栏方向(如果需要) override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return .portrait } }
步骤2:包装为SwiftUI的View
import SwiftUI import SpriteKit struct LockedPortraitSpriteView: UIViewControllerRepresentable { var scene: SKScene func makeUIViewController(context: Context) -> LockedPortraitSKViewController { let vc = LockedPortraitSKViewController() vc.scene = scene // 设置ViewController的view为SKView vc.view = SKView(frame: UIScreen.main.bounds) return vc } func updateUIViewController(_ uiViewController: LockedPortraitSKViewController, context: Context) { // 如需更新场景可在此处理 } }
使用方式
在你的SwiftUI视图中,用LockedPortraitSpriteView替代原来的SpriteView:
struct GameView: View { var body: some View { LockedPortraitSpriteView(scene: YourGameScene(size: UIScreen.main.bounds.size)) .ignoresSafeArea() } }
这样设置后,系统会直接锁定竖屏,不会出现“先旋转再纠正”的现象,因为控制器从一开始就拒绝了非竖屏的旋转请求。
二、强制竖屏后读取真实设备方向
即使锁定了界面方向,依然可以读取设备的真实物理方向,只需监听UIDevice的方向通知:
实现代码示例(在SKScene中)
import SpriteKit class YourGameScene: SKScene { override func didMove(to view: SKView) { // 开启设备方向通知 UIDevice.current.beginGeneratingDeviceOrientationNotifications() NotificationCenter.default.addObserver( self, selector: #selector(deviceOrientationChanged(_:)), name: UIDevice.orientationDidChangeNotification, object: nil ) } @objc private func deviceOrientationChanged(_ notification: Notification) { let orientation = UIDevice.current.orientation // 过滤有效方向(排除未知、正面朝上/朝下的状态) switch orientation { case .portrait: print("设备竖屏(正方向)") // 执行你的自定义调整逻辑 case .portraitUpsideDown: print("设备倒竖屏") case .landscapeLeft: print("设备左横屏") case .landscapeRight: print("设备右横屏") default: // 忽略无效状态 break } } deinit { // 记得移除通知,避免内存泄漏 UIDevice.current.endGeneratingDeviceOrientationNotifications() NotificationCenter.default.removeObserver(self) } }
注意事项
UIDevice.current.orientation会返回所有可能的设备状态,包括.unknown、.faceUp、.faceDown,需要根据你的需求过滤有效方向。- 即使界面被锁定为竖屏,设备的物理方向检测依然正常工作,不会受界面锁定影响。
内容的提问来源于stack exchange,提问作者wjd
相关产品推荐
相关产品推荐

