GarySabo GarySabo - 3 months ago 27
iOS Question

Setting preferred focus in TVOS on an SKSpriteNode?

Since I'm working in SpriteKit, my buttons are

...however I find myself in a situation where I need to set focus in my
via overriding
. Is there a way to downcast an
to a
? If so I haven't been able to figure out yet...any alternative?

let playButton = SKSpriteNode(imageNamed: "PlayButton")
playButton.position = CGPoint(x: scene.size.width * 0.25, y: scene.size.height * 0.25)
playButton.zPosition = Layer.UI.rawValue

override var preferredFocusedView: UIView? {
get {
return //playButton how?


Focus navigation is only now supported with tvOS 10 and SpriteKit, prior to that you had to do it manually using your own focus system.

For that reason preferred focus view is depreciated because it only supports UIViews. You should now use preferred focus environments instead.

First thing you do is in your GameViewController set the preferred focus environment to the first presented scene.

class GameViewController: UIViewController {

     static var currentScene: SKScene? // static because I have multiple scenes and need to change this value easily

      override func viewDidLoad() {

           let scene = StartScene(...)
           GameViewController.currentScene = scene

      override var preferredFocusEnvironments: [UIFocusEnvironment] {
           if let scene = GameViewController.currentScene {
               return [scene]

           return []

Than in your 1st SKScene you can set the focus environment to your playButton.

 override var preferredFocusEnvironments: [UIFocusEnvironment] {
         return [playButton]

You play button should be a subclass of SKSpriteNode that you use for all your buttons in your game. Use enums and give them different names or identifiers to distinguish between them.

 class Button: SKSpriteNode {

      var isFocusable = true // easy way to later turn off focus for your buttons e.g. when overlaying menus etc.

      /// Can become focused
      override open var canBecomeFocused: Bool {
          return isFocusable

      /// Did update focus
      override open func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {

          if context.previouslyFocusedItem === self {
              // SKAction to reset focus animation for unfocused button

          if context.nextFocusedItem === self {
               // SKAction to run focus animation for focused button

For more detail you should read this question and answer I posted recently.

TVOS 10 SpriteKit Focus Navigation default focused item

You should also read this article

and watch the 2016 apple keynote called "Whats New in SpriteKit" where they talk about it half way through.

Hope this helps