'Handling focus event changes on tvOS in SwiftUI

How do I respond to focus events on tvOS in SwiftUI?

I have the following SwiftUI view:

struct MyView: View {
    var body: some View {
        VStack {
            Button(action: {
                print("Button 1 pressed")
            }) {
                Text("Button 1")
            }.focusable(true) { focused in
                print("Button 1 focused: \(focused)")
            }
            Button(action: {
                print("Button 2 pressed")
            }) {
                Text("Button 2")
            }.focusable(true) { focused in
                print("Button 2 focused: \(focused)")
            }
        }
}

Clicking either of the buttons prints out correctly. However, changing focus between the two buttons does not print anything.

This guy is doing the same thing with rows in a list & says it started working for him with the Xcode 11 GM, but I'm on 11.5 and it's definitely not working (at least not for Buttons (or Toggles - I tried those too)).

Reading the documentation, this appears to be the correct way to go about this, but it doesn't seem to actually work. Am I missing something, or is this just broken?



Solution 1:[1]

In case anybody else stumbles upon this question, the answer is to make your view data-focused

So, if you have a list of movies in a scrollview, you would add this to your outer view:

var myMovieList: [Movie];
@FocusState var selectedMovie: Int?;

And then somewhere in your body property:

ForEach(0..<myMovieList.count) { index in 
    MovieCard(myMovieList[i])
        .focusable(true)
        .focused($selectedMovie, equals: index)
}

.focusable() tells the OS that this element is focusable, and .focused tells it to make that view focused when the binding variable ($selected) equals the value passed to equals: ...

For example on tvOS, if you wrap this in a scrollview and press left/right, it will change the selection and update the selected index in the $selectedMovie variable; you can then use that to index into your movie list to display extra info.

Here is a more complete example that will also scale the selected view:

https://pastebin.com/jejwYxMU

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ian