alexy
alexy

Reputation: 29

Focus on the specific item in the List on SwiftUI (tvOS)

I am having a hard time trying to figured out how to focus on a specific cell/row in the list in the SwiftUI 2.0 and tvOS 14. I need to be able to focus and select a specific record when I am navigated to a view. However when the focus is switched to the list, some random row is focused. I've tried ScrollView and List to create a list of items with Buttons as items and with appropriate prefersDefaultFocus. Nothing works. Here's some sample code:

struct ChannelListView: View {
    @Namespace private var namespace
    @ObservedObject var viewModel : LiveViewModel
    @State var selection = Set<ChannelItem>()
    var body: some View {
        List(viewModel.channels, selection: $selection){ item in
            ScrollViewReader { proxy in
                        Button(action: {
                        }){
                            ChannelItemView(item: item, selectedItem: $viewModel.selectedChannel, onSelected: { id in
                            })
                            .padding(.vertical, 2)
                        }
                        .buttonStyle(ChannelButtonStyle())
                        .prefersDefaultFocus(item == viewModel.selectedChannel, in: namespace)
            }
        }
        .focusScope(namespace)
    }
}

Upvotes: 1

Views: 1622

Answers (1)

Alex Overseer
Alex Overseer

Reputation: 511

Found a way to achieve it. Using the defaultFocus modifier does the trick. You need to supply the desired element from the list as its argument, plus you need to specify the priority as .userInitiated, without it, it doesn't work correctly. Plus, we track which was the last focused (aka remembersLastFocusedIndexPath from UIKit)

@main
struct FocusApp: App {
    var body: some Scene {
        WindowGroup {
            VStack(spacing: 50) {
                CustomRow()
                CustomRow()
            }
        }
    }
}

struct CustomRow: View {
    let items = [1, 2, 3, 4]

    @FocusState private var currentFocusItem: Int?
    @State private var lastFocusItem: Int?

    var body: some View {
        ScrollView(.horizontal) {
            LazyHStack(spacing: 50) {
                ForEach(items, id: \.self) { item in
                    Button { } label: {
                        Text("Item \(item)")
                            .frame(width: 300, height: 300, alignment: .center)
                            .background(Color.red)
                    }
                    .focused($currentFocusItem, equals: item)
                }
            }
        }
        .defaultFocus($currentFocusItem, lastFocusItem ?? items.first, priority: .userInitiated)
        .onChange(of: currentFocusItem) {
            if currentFocusItem != nil {
                lastFocusItem = currentFocusItem
            }
        }
    }
}

Upvotes: 0

Related Questions