SwiftUI双击手势搭配NavigationLink跳转DetailView出现随机匹配问题
问题根因
- 全局状态共用错误:你将跳转控制状态
isDoubleTab定义在Home视图的顶层,ForEach循环生成的所有列表项对应的NavigationLink都绑定了这同一个布尔值。任意列表项双击触发状态变为true时,所有列表项的NavigationLink会同时响应跳转,系统最终只会渲染最后一个命中的NavigationLink对应页面,所以出现数据不匹配的随机跳转现象。 - 代码笔误:示例中存在多处拼写错误会额外导致运行异常,包括:
onTapGesture中调用的isDoubleTapped和实际定义的状态名isDoubleTab不一致、NavigationLink参数isActivate应为isActive、视图名VStact/HSTack拼写错误、DetailView中data属性类型声明错误等。
修复方案
推荐使用可选类型存储当前选中的列表项,替代全局布尔跳转状态,避免多个NavigationLink绑定同一状态的冲突问题,以下是兼容iOS14+的修复代码:
import SwiftUI struct DataArray: Identifiable { let id = UUID() let number: Int let cities: String var name1: String? var name2: String? var name3: String? var name4: String? } public struct ListDataArray { static var dot = [ DataArray(number: 1, cities: "Baltimore", name1: "John", name2: "Mike"), DataArray(number: 2, cities: "Frederick"), DataArray(number: 3, cities: "Catonsville", name1: "Susan", name2: "Oliver", name3: "Jude", name4: "Erik"), ] } struct Home: View { var datas: [DataArray] = ListDataArray.dot // 替换布尔状态为可选选中项 @State var selectedItem: DataArray? var body: some View { NavigationView { LazyVStack(spacing: 10) { ForEach(datas) { data in HomeView(data: data) .onTapGesture(count: 2) { // 双击时赋值当前选中项 selectedItem = data } Divider() .padding() } } // 全局只放一个NavigationLink绑定可选状态 .background( NavigationLink( destination: selectedItem != nil ? DetailView(data: selectedItem!) : nil, isActive: Binding( get: { selectedItem != nil }, set: { if !$0 { selectedItem = nil } } ) ) { EmptyView() } ) .navigationBarHidden(true) } } } struct DetailView: View { // 修正属性声明错误 var data: DataArray var body: some View { // 修正拼写错误 VStack { Text(data.cities) } } } struct HomeView: View { var data: DataArray var body: some View { VStack { // 修正拼写错误 HStack { Text(data.cities).padding() // 可选值安全处理 if let name1 = data.name1 { Text(name1) } if let name2 = data.name2 { Text(name2) } } } } }
如果你的项目最低支持iOS16及以上,可以直接用navigationDestination修饰符实现,代码更简洁:
只需要把Home视图的body修改为:
var body: some View { NavigationStack { // 替换NavigationView为NavigationStack LazyVStack(spacing: 10) { ForEach(datas) { data in HomeView(data: data) .onTapGesture(count: 2) { selectedItem = data } Divider() .padding() } } .navigationDestination(item: $selectedItem) { item in DetailView(data: item) } .navigationBarHidden(true) } }
内容的提问来源于stack exchange,提问作者Lian
相关产品推荐
相关产品推荐

