SwiftUI双击手势无法更新选中列表项对应弹出菜单如何解决
核心问题原因
你的代码有三个关键问题导致弹窗永远显示第一个元素:
- 全局状态
Tapping仅存储了「是否显示弹窗」的布尔值,没有存储当前选中的列表项 - 双击手势加在了整个
ForEach的外层,无法拿到点击对应位置的具体数据 ContentView中弹出DetailMenu时写死了取数组第0个元素ListDataArray.dot[0]
完整修改方案
1. 调整全局状态类Tapping,新增选中项存储
class Tapping: ObservableObject { @Published var isDoubleTab = false // 存储当前双击选中的列表项 @Published var selectedItem: DataArray? }
2. 修改Home视图,将双击手势绑定到每个单独的列表项
同时修正你代码中的笔误(ForEach遍历对象写错、cities属性不需要可选绑定)
struct Home: View { @EnvironmentObject var tap: Tapping var datas: [DataArray] = ListDataArray.dot var body: some View { ScrollView { LazyVStack(spacing: 10) { ForEach(datas, id: \.id) { data in // 每个列表项单独包容器,绑定对应数据的双击手势 VStack(spacing: 4) { if let data1 = data.name1 { Text(data1) } Text(data.cities) if let data2 = data.name2 { Text(data2) } } .onTapGesture(count: 2) { // 存储当前选中项后再打开弹窗 tap.selectedItem = data tap.isDoubleTab = true } } } } } }
3. 修正ContentView,动态传入选中的列表项
修正笔误(类名少字母、未注入全局状态)
struct ContentView: View { @EnvironmentObject var tap: Tapping var body: some View { ZStack { // 底层始终显示Home页面,不需要切换显示逻辑 Home() // 仅当弹窗开启且选中项不为空时显示菜单 if tap.isDoubleTab, let selectedItem = tap.selectedItem { DetailMenu(dataArr: selectedItem) .background(.ultraThinMaterial) .cornerRadius(12) } } } }
4. 修正DetailMenu的属性和视图引用错误
修正笔误(属性定义错误、VStack拼写错误、不存在的lyric变量)
struct DetailMenu: View { // 正确定义接收的参数类型 var dataArr: DataArray @EnvironmentObject var tap: Tapping var body: some View { VStack(spacing: 20) { Text(dataArr.name1 ?? "无对应名称") HStack(spacing: 40) { Button(action: { tap.isDoubleTab = false // 关闭时清空选中项避免复用异常 tap.selectedItem = nil }, label: { Image(systemName: "suit.heart") .font(.title) }) Button(action: { tap.isDoubleTab = false tap.selectedItem = nil }, label: { Image(systemName: "gear") .font(.title) }) } .padding() } .padding(30) } }
5. 补充原有数组定义的语法错误
你原代码中ListDataArray的数组成员初始化少了逗号,补充后即可正常编译:
public struct ListDataArray { static var dot = [ DataArray(number: 1, cities: "Baltimore", // 补逗号 name1: "A", name2: "B"), DataArray(number: 2, cities: "Frederick"), DataArray(number: 3, cities: "Catonsville", // 补逗号 name1: "Aa", name2: "Bb", name3: "Cc", name4: "Dd"), ] }
最后别忘了在项目入口注入全局状态
@main struct YourAppName: App { @StateObject private var tap = Tapping() var body: some Scene { WindowGroup { ContentView() .environmentObject(tap) } } }
内容的提问来源于stack exchange,提问作者Lian
相关产品推荐
相关产品推荐

