tvOS SwiftUI嵌入SpriteKit场景,如何配置焦点引擎实现遥控器导航?
解决方案:在tvOS SwiftUI中实现SpriteKit节点的焦点导航
1. 自定义SpriteView的UIKit桥接(处理焦点传递)
默认的SpriteView无法正确将焦点事件传递给SKScene,需要自定义UIViewRepresentable封装SKView,确保焦点能向下传递到场景节点:
import SwiftUI import SpriteKit struct FocusableSpriteView: UIViewRepresentable { var scene: SKScene func makeUIView(context: Context) -> SKView { let skView = SKView() skView.scene = scene skView.isUserInteractionEnabled = true // 允许SKView接收焦点,以便传递给子节点 skView.isFocusable = true return skView } func updateUIView(_ uiView: SKView, context: Context) {} }
2. 配置SKScene和可聚焦节点
在SwatchGridScene中,给每个需要导航的节点开启可聚焦属性,并实现焦点相关回调:
class SwatchGridScene: SKScene { override func didMove(to view: SKView) { super.didMove(to: view) // 初始化3x5网格节点 let gridSize = CGSize(width: 100, height: 100) let spacing: CGFloat = 20 for row in 0..<3 { for col in 0..<5 { let node = SKShapeNode(rectOf: gridSize) node.fillColor = .random() node.strokeColor = .clear // 标记节点可被焦点引擎识别 node.isFocusable = true // 设置网格布局位置 node.position = CGPoint( x: frame.midX + (CGFloat(col) - 2) * (gridSize.width + spacing), y: frame.midY + (CGFloat(row) - 1) * (gridSize.height + spacing) ) addChild(node) } } } // 处理焦点切换逻辑 override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { super.didUpdateFocus(in: context, with: coordinator) // 重置失焦节点颜色 if let previousNode = context.previouslyFocusedItem as? SKShapeNode { previousNode.fillColor = .random() } // 高亮聚焦节点 if let nextNode = context.nextFocusedItem as? SKShapeNode { nextNode.fillColor = .white } } // 处理遥控器确认按键事件 override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) { guard let press = presses.first, press.type == .select else { return } if let focusedNode = focusedChild as? SKShapeNode { // 这里添加节点被选中后的业务逻辑 print("选中节点位置:\(focusedNode.position)") } } } // 扩展UIColor生成随机颜色,用于节点视觉区分 extension UIColor { static func random() -> UIColor { UIColor( red: CGFloat.random(in: 0.3...1), green: CGFloat.random(in: 0.3...1), blue: CGFloat.random(in: 0.3...1), alpha: 1 ) } }
3. 在SwiftUI视图中使用自定义组件
替换原SpriteView为自定义的FocusableSpriteView,并开启SwiftUI层面的可聚焦属性:
struct SwatchGridSceneView: View { private let scene = SwatchGridScene() var body: some View { GeometryReader { geometry in FocusableSpriteView(scene: scene) .frame(width: geometry.size.width, height: geometry.size.height) // 让SwiftUI视图允许焦点进入SpriteKit层级 .focusable() } } } @main struct ColourGameApp: App { var body: some Scene { WindowGroup { SwatchGridSceneView() } } }
关键要点
- 焦点传递链路:自定义
FocusableSpriteView让SKView成为可聚焦UI元素,SwiftUI的.focusable()确保焦点能从SwiftUI层进入SpriteKit场景。 - 节点可聚焦标记:必须给每个需要导航的
SKNode设置isFocusable = true,否则焦点引擎会忽略该节点。 - 视觉反馈:通过
didUpdateFocus处理焦点切换时的UI变化,让用户清晰感知当前焦点位置。 - 交互事件:
pressesEnded方法处理遥控器确认按键,实现节点选中逻辑。
内容的提问来源于stack exchange,提问作者Jacob King
相关产品推荐
相关产品推荐

