SwiftUI问题:Form将List中所有NavigationLink一次性推入导航栈
在SwiftUI开发中,当尝试用Form包裹包含NavigationLink的List实现设置视图时,会出现异常:List内所有NavigationLink对应的ID会被一次性推入NavigationStack的导航栈,而非仅在点击Link时才执行入栈操作。
正常行为代码
struct NumberView: View { @Binding var navigationPath: [Int] var number: Int var max: Int var body: some View { let next: Int = number < max ? number + 1 : 1 return Form { Section { Text("当前页面编号:\(number)") NavigationLink("跳转到编号:\(next)", value: next) Button("返回上一页") { print("navigationPath: \(navigationPath)") navigationPath.removeLast() } Button("返回根页面") { print("navigationPath: \(navigationPath)") navigationPath.removeAll() } } .navigationTitle("选择编号") } } } struct SettingsView: View { @State var navigationPath: [Int] = [] private let numberArray: [Int] = [1, 2, 3, 4] var body: some View { NavigationStack (path: $navigationPath) { List(numberArray, id: \.self) { number in NavigationLink("选择编号:\(number)", value: number) } .navigationDestination(for: Int.self) { number in NumberView(navigationPath: $navigationPath, number: number, max: numberArray.max()!) } .navigationTitle("选择你的编号") } } }
异常行为代码
struct SettingsView: View { @State var navigationPath: [Int] = [] private let numberArray: [Int] = [1, 2, 3, 4] var body: some View { NavigationStack (path: $navigationPath) { Form { List(numberArray, id: \.self) { number in NavigationLink("选择编号:\(number)", value: number) } .navigationDestination(for: Int.self) { number in NumberView(navigationPath: $navigationPath, number: number, max: numberArray.max()!) } } .navigationTitle("选择你的编号") } } }
问题原因
Form本质是SwiftUI提供的特殊List实现,内部已经包含了列表的布局与交互逻辑。当在Form中嵌套List时,会造成视图层级冲突,干扰NavigationLink的点击触发机制,导致所有Link对应的ID被一次性推入导航栈。
解决方法
方法1:直接使用Form替代List
无需在Form中嵌套List,直接通过ForEach在Form内生成NavigationLink,既保留Form的样式,又保证交互正常:
struct SettingsView: View { @State var navigationPath: [Int] = [] private let numberArray: [Int] = [1, 2, 3, 4] var body: some View { NavigationStack (path: $navigationPath) { Form { ForEach(numberArray, id: \.self) { number in NavigationLink("选择编号:\(number)", value: number) } } .navigationDestination(for: Int.self) { number in NumberView(navigationPath: $navigationPath, number: number, max: numberArray.max()!) } .navigationTitle("选择你的编号") } } }
方法2:用List模拟Form样式
如果需要保留List的特定特性,可以给List添加.formStyle(.grouped)修饰符,模拟Form的分组样式,同时避免层级冲突:
struct SettingsView: View { @State var navigationPath: [Int] = [] private let numberArray: [Int] = [1, 2, 3, 4] var body: some View { NavigationStack (path: $navigationPath) { List(numberArray, id: \.self) { number in NavigationLink("选择编号:\(number)", value: number) } .formStyle(.grouped) .navigationDestination(for: Int.self) { number in NumberView(navigationPath: $navigationPath, number: number, max: numberArray.max()!) } .navigationTitle("选择你的编号") } } }
内容的提问来源于stack exchange,提问作者RG128
相关产品推荐
相关产品推荐

