You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何在ForEach循环内传递选中项的指定值

问题解决方案:列表项选中后Sheet传递错误标识符

问题原因

你当前的代码存在两个核心问题:

  1. 在ForEach循环内给每个按钮都绑定了同一个showSheet状态和onChange监听,当点击任意按钮触发showSheet变为true时,所有循环中的onChange闭包都会执行一遍,最终theIdentifer会被最后一个循环项的row值覆盖。
  2. 每个循环项都单独绑定了sheet,这会导致多个Sheet实例被创建,进一步加剧状态覆盖的问题。

解决方案一:使用sheet(item:)(推荐)

这种方式专门用于绑定选中项的场景,无需额外的布尔状态控制Sheet显示,直接绑定选中的数据源项。

修改后的完整代码

struct Test: View {
    @StateObject var vm = ViewModel()
    
    var body: some View {
        VStack {
            ForEach(vm.someData, id: \.self) { row in
                Button {
                    vm.selectedRow = row // 点击时直接赋值选中项
                } label: {
                    Text("\(row)")
                }
            }
        }
        .padding()
        // 绑定选中项,非nil时自动展示Sheet
        .sheet(item: $vm.selectedRow) { selectedRow in
            TheSheet(selectedRow: selectedRow)
        }
    }
}

extension Test {
    @MainActor class ViewModel: ObservableObject {
        @Published var selectedRow: Int? // 存储选中项,可选类型
        @Published var someData = [2, 4, 6, 8, 10, 12]
    }
}

struct TheSheet: View {
    let selectedRow: Int
    @Environment(\.dismiss) private var dismiss // 用环境变量关闭Sheet
    
    var body: some View {
        VStack {
            Text("选中的标识符:\(selectedRow)")
            Button {
                dismiss() // 关闭Sheet,selectedRow会自动置为nil
            } label: {
                Text("Close")
            }
        }
        .frame(width: 400, height: 200)
    }
}

// 让Int遵循Identifiable协议,满足sheet(item:)的要求
extension Int: Identifiable {
    public var id: Int { self }
}

解决方案二:保留isPresented的修复方案

如果坚持使用布尔状态控制Sheet,需要将sheet移出循环,并在按钮点击时直接完成赋值操作,避免多个onChange触发覆盖。

修改后的核心代码

struct Test: View {
    @StateObject var vm = ViewModel()
    
    var body: some View {
        VStack {
            ForEach(vm.someData, id: \.self) { row in
                Button {
                    vm.theIdentifer = row // 先赋值选中项
                    vm.showSheet.toggle() // 再打开Sheet
                } label: {
                    Text("\(row)")
                }
            }
        }
        .padding()
        // 将sheet移到循环外,只绑定一次
        .sheet(isPresented: $vm.showSheet) {
            TheSheet(vm: vm)
        }
    }
}

extension Test {
    @MainActor class ViewModel: ObservableObject {
        @Published var showSheet = false
        @Published var theIdentifer = 0
        @Published var someData = [2, 4, 6, 8, 10, 12]
    }
}

// TheSheet代码保持不变

内容的提问来源于stack exchange,提问作者Steve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 04:55:07