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

Swift中自定义视图的List选中功能失效问题排查

解决SwiftUI List自定义结构体项选中失效问题

问题原因

你的testData结构体虽然遵循了Hashable,但Swift自动合成的Equatable/Hashable实现会对比所有存储属性(name和id)。而你在List中指定了id: \.id,意味着List通过id识别行,但选中时SwiftUI需要匹配数据源中的testData实例与selection绑定的实例是否相等。由于默认的相等性判断同时检查name和id,导致实例匹配失败,选中功能完全失效。

解决方法

手动实现Hashable和Equatable,让判断仅基于唯一标识id,同时将id改为不可变的let类型,避免后续被意外修改:

struct testData: Hashable {
    var name = ""
    let id = UUID() // 改为let,保证标识唯一性
    
    // 仅基于id判断相等性
    static func == (lhs: testData, rhs: testData) -> Bool {
        lhs.id == rhs.id
    }
    
    // 仅基于id生成哈希值
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
}

修改后,ListTest2的选中功能即可正常工作,底部文本也会正确显示选中项的名称。

补充说明

如果是在iOS平台开发,List的单选项选中默认需要开启编辑模式才能生效,可以通过添加工具栏按钮实现:

struct ListTest2: View {
    @State private var selection: testData?
    @State private var isEditing = false
    
    let names = [
        testData(name: "Cyril"),
        testData(name: "Lana"),
        testData(name: "Mallory"),
        testData(name: "Sterling")
    ]
    
    var body: some View {
        NavigationStack {
            VStack {
                List(names, id: \.id, selection: $selection) { contact in
                    Text(contact.name)
                }
                .navigationTitle("Contacts")
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button(isEditing ? "Done" : "Edit") {
                            isEditing.toggle()
                        }
                    }
                }
                .environment(\.editMode, .constant(isEditing ? .active : .inactive))
                
                Text("\(selection?.name ?? "N/A")")
            }
        }
    }
}

根据你第一个示例的运行表现,推测你是在macOS环境下开发,该平台的List默认支持点击选中,无需额外开启编辑模式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:41:16