Summary:
When using the new .focused modifier to track focus within a large LazyVStack or LazyHStack, we observe a major frame-rate drop and stuttering on Apple TV (1st and 2nd generation).
Steps to Reproduce:
- Create a LazyVStack (or LazyHStack) displaying a substantial list of data models (e.g., 100+ GroupData items).
- Attach the .focused(::) modifier to each row, binding to an @FocusState variable of the same model type.
- Build and run on an Apple TV device or simulator.
- Scroll through the list using the remote.
static func == (lhs: GroupData, rhs: GroupData) -> Bool {
lhs.id == rhs.id
}
var id: String
var name: String
var subName: String
var subGroup: [GroupData] = []
var logo: URL?
}
struct TestView: View {
@FocusState var focusedGroup: GroupData?
let groupsArr: [GroupData]
var body: some View {
ScrollView {
LazyVStack {
ForEach(groupsArr, id: \.id) { group in
Button {
} label: {
GroupTestView(group: group)
}
.id(group.id)
.focused($focusedGroup, equals: group)
}
}
}
}
}
struct GroupTestView: View {
let group: GroupData
var body: some View {
HStack {
KFImage.url(group.logo)
.placeholder {
Image(systemName: "photo")
.opacity(0.2)
.imageScale(.large)
}
.resizable()
.scaledToFit()
.frame(width: 70)
VStack {
Text(group.name)
Text(group.subName)
}
}
}
}
Expected Behavior
- Scrolling remains smooth (60 fps) regardless of list size.
- Focus updates without introducing visible lag.
Observed Behavior
- Frame rate drops significantly when .focused is applied.
- Scrolling becomes visibly laggy, especially on older Apple TV hardware.
- Even when binding an @FocusState<String?> (storing only the id), performance improves slightly but remains suboptimal.
Workarounds Tried
- Switched to @FocusState of type String to track only the ID of each group, this has helped but there is still a big performance decrease.
- Minimised view-body complexity and removed other modifiers.
- Verified that excluding .focused entirely restores smooth scrolling.
Any guidance or suggestions would be greatly appreciated.