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

如何从SpriteKit的SKScene场景中弹出展示SwiftUI视图

从SpriteKit场景弹出SwiftUI视图的实现方案

推荐实现方案(状态驱动,全SwiftUI风格)

因为你的SKScene本身是由SwiftUI视图承载的,最符合SwiftUI声明式编程规范的方式是通过状态变量控制弹窗显隐,完全不用手写UIKit的addSubview逻辑。

步骤1:修改SKScene子类,添加交互回调

在你的SKScene子类中新增回调属性,替换原来的视图添加/移除逻辑:

class GameScene: SKScene {
    // 新增回调,用于通知SwiftUI层切换弹窗显隐状态
    var toggleInstructionsPopUp: (() -> Void)?
    // 保留你原有的其他属性定义...
    
    // 原有触摸检测逻辑修改如下
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let location = touches.first?.location(in: self) else { return }
        if bloqsLogo.contains(location) {
            // 直接调用回调,把显隐控制逻辑交给SwiftUI层处理
            toggleInstructionsPopUp?()
        }
    }
}

步骤2:在承载SKScene的SwiftUI视图中添加状态控制

定义状态变量控制弹窗显隐,同时给SKScene的回调赋值:

struct GameHostView: View {
    // 控制指令弹窗显隐的状态变量
    @State private var showInstructions = false
    // 实例化你的SKScene
    private let gameScene: GameScene = {
        let scene = GameScene(size: CGSize(width: 1080, height: 1920))
        scene.scaleMode = .aspectFill
        return scene
    }()
    
    var body: some View {
        ZStack {
            // 承载SpriteKit游戏场景
            SpriteView(scene: gameScene)
                .ignoresSafeArea()
        }
        // 绑定状态,直接用SwiftUI原生组件渲染弹窗
        .sheet(isPresented: $showInstructions) {
            // 这里传入你开发的SwiftUI版弹窗视图即可
            InstructionsPopUp()
        }
        .onAppear {
            // 给SKScene的回调赋值,触发时切换显隐状态
            gameScene.toggleInstructionsPopUp = {
                showInstructions.toggle()
            }
        }
    }
}

该方案的优势:

  • 所有UI逻辑都用SwiftUI实现,符合你的技术栈要求
  • 不需要手动管理视图的添加/移除、tag标记,避免内存泄漏风险
  • 可以直接使用SwiftUI的sheet、popover、自定义overlay等任意弹窗样式

备选方案(兼容UIKit加Subview的写法)

如果你要沿用原有的addSubview逻辑,需要把SwiftUI视图用UIHostingController包装后再添加:

if bloqsLogo.contains(location) {
    if instructionsOn == false {
        // 把SwiftUI视图包装成UIKit可识别的视图
        let hostingVC = UIHostingController(rootView: InstructionsPopUp())
        hostingVC.view.tag = 104
        hostingVC.view.frame = self.view?.bounds ?? .zero
        hostingVC.view.backgroundColor = .clear
        self.view?.addSubview(hostingVC.view)
        instructionsOn = true
    } else {
        if let viewWithTag = self.view!.viewWithTag(104) {
            viewWithTag.removeFromSuperview()
            instructionsOn = false 
        } else {
            print("nah")
        }
    }
}

注意该方案需要手动处理UIHostingController的生命周期,避免内存泄漏,更推荐使用第一种状态驱动的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 19:06:03