In tvOS when using NavigationStack inside NavigationSplitView as below:
@State private var selectedItem: String?
@State private var navigationPath = NavigationPath() // Track navigation state manually
var body: some View {
NavigationSplitView {
List(selection: $selectedItem) {
Button("Item 1") { selectedItem = "Detail View 1" }
Button("Item 2") { selectedItem = "Detail View 2" }
}
} detail: {
NavigationStack(path: $navigationPath) {
DetailView()
.navigationDestination(for: String.self) { value in
Text("New Screen: \(value)")
}
}
}
}
}
This example completely breaks the animation inside NavigationStack while navigating between different views, using withAnimation also breaks the navigation as the old view seems to be still in stack and is shown in the new view background.
I have also submitted bug report: https://feedbackassistant.apple.com/feedback/16933927
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
According to the docs tvOS 18+ supports the new NavigationTransition and the matchedTransitionSource and navigationTransition(.zoom(sourceID: id, in: namespace)) modifiers, however they don't seems to work.
Taking the DestinationVideo project example from the latest WWDC the matchedTransitionSourceis marked with #if os(iOS)
Is it supported by tvOS or is it for iOS only?
https://developer.apple.com/documentation/swiftui/view/navigationtransition(_:)
https://developer.apple.com/documentation/swiftui/view/matchedtransitionsource(id:in:configuration:)
When attempting to replicate the tvOS Settings menu layout, where the screen is divided horizontally into two sections, placing a NavigationStack or a Form view on either side of the screen causes focusable views (such as Button, TextField, Toggle, etc.) to be visually clipped when they receive focus and apply the default scaling animation.
Specifically:
If the Form or NavigationStack is placed on the right side, the left edge of the focused view gets clipped.
If placed on the left side, the right edge of the focused view gets clipped.
This issue affects any focusable child view inside the Form or NavigationStack when focus scaling is triggered.
Example code:
struct TVAppMenuMainView: View {
var body: some View {
VStack {
Text("Settings Menu")
.font(.title)
HStack {
VStack {
Text("Left Pane")
}
.frame(width: UIScreen.main.bounds.width * 0.4) // represents only 40% of the screen
.frame(maxHeight: .infinity)
.padding(.bottom)
Divider()
NavigationStack {
Form { // All the buttons will get cut on the left side when each button is focused
Button("First Button"){}
Button("Second Button"){}
Button("Third Button"){}
Button("Forth Button"){}
}
}
}
.frame(maxHeight: .infinity)
.frame(maxWidth: .infinity)
}
.background(.ultraThickMaterial)
}
}
How it looks:
What I have tried:
.clipped modifiers
.ignoresSafeArea
Modifying the size manually
Using just a ScrollView with VStack works as intended, but as soon as NavigationStack or Form are added, the buttons get clipped.
This was tested on the latest 18.5 tvOS BETA
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.
The following shows minimal example to reproduce the issue:
Menu {
Button("Test"){}
} label: {
Text("Menu")
} primaryAction: {
// Some action
}
primaryAction modifier will not be called when pressing the menu button/view on iOS 26 beta, long pressing it will open the menu.
Was tested on latest iOS 26 beta 8
Topic:
UI Frameworks
SubTopic:
SwiftUI