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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 22:54:36