SwiftUI tvOS应用中多组NavigationLink无法同时交互的解决方法咨询
嘿,我之前开发tvOS SwiftUI应用时也碰到过几乎一模一样的问题!这种情况大概率是NavigationLink的导航目标(navigationDestination)放置层级不对,再加上tvOS特有的焦点管理机制在搞鬼。
先帮你分析下问题根源:
你现在把.navigationDestination修饰在了ForEach的后面,这会让这个导航目标的作用域被局限在ScrollView范围内,相当于把整个ScrollView变成了一个独占导航上下文的容器,直接干扰了Header里Edit按钮的焦点可用性。而且tvOS的焦点系统本来就对容器视图的交互优先级很敏感,当ScrollView占据大部分屏幕空间时,会默认抢占其他区域的焦点检测,导致Edit按钮根本接收不到焦点事件。
给你几个亲测有效的修复步骤:
1. 调整navigationDestination的位置
把针对TestSources的.navigationDestination从ForEach后面移到整个VStack的末尾,也就是放在NavigationStack的直接子视图上,这样所有NavigationLink的导航目标都处于同一个全局作用域,不会互相抢占上下文。
2. 统一NavigationLink的写法(可选但推荐)
你现在混合使用了两种NavigationLink写法:Header里是直接传destination参数的旧写法,ScrollView里是value+navigationDestination的新写法。建议把Edit按钮也改成新写法,统一用navigationDestination管理,这样更符合SwiftUI导航规范,也能避免潜在冲突。
3. 增强Header区域的焦点可识别性
可以给Edit按钮添加明确的按钮样式,或者调整布局的padding/frame,让tvOS焦点系统更容易识别这个可交互元素。
下面是修改后的完整代码,关键改动处已标注:
import SwiftUI struct TestSources: Hashable { let id = UUID() let name: String } struct SourcesView: View { private var Sources = [TestSources(name: "Computer 1"), TestSources(name: "Computer 2")] var columns: [GridItem] { Array(repeating: .init(.adaptive(minimum: 200)), count: 2) } var body: some View { NavigationStack { VStack(alignment: .center) { // Header HStack(alignment: .center){ Label("Sources", systemImage: "externaldrive.connected.to.line.below") .font(.headline) .frame(maxWidth: .greatestFiniteMagnitude, alignment: .leading) .padding(.all) // 改成value写法,统一用navigationDestination管理 NavigationLink("Edit", value: "edit") .buttonStyle(CardButtonStyle()) // 添加按钮样式,增强焦点识别 } Divider() ScrollView(.vertical, showsIndicators: false) { LazyVGrid(columns: columns, spacing: 10) { ForEach(Sources.indices, id: \.self) { index in NavigationLink(Sources[index].name ,value: Sources[index]) } .accentColor(Color.black) .padding(Edge.Set.vertical, 20) } .padding(.horizontal) } } .frame( minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading ) // --- 关键改动:把两个navigationDestination都放在VStack后面 --- .navigationDestination(for: TestSources.self) { source in TestShareView(source: source) } .navigationDestination(for: String.self) { value in if value == "edit" { TestEditView() } } } } } struct TestEditView: View { var body: some View { Text("Edit") } } struct TestShareView: View { let source : TestSources var body: some View { Text(source.name) } }
如果还是有问题,你可以试试给Header的HStack设置固定高度,比如.frame(height: 60),确保它不会被ScrollView挤压,同时让焦点系统更容易定位到这个区域。
备注:内容来源于stack exchange,提问作者I'm Just a Bill

