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

在VStack嵌套可选项时保留SwiftUI List的选中状态

解决SwiftUI List嵌套容器后选中功能失效的问题

当List内部嵌套VStack这类容器时,List会把整个VStack识别为单个列表行,而非把内部ForEach的每个子项当作独立行,这就导致选中功能和键盘导航失效。可以通过以下两步解决:

  • 给外层容器添加.listRowInsets(EdgeInsets()),消除容器自带的行边距,让内部子项完全占据行空间
  • 给每个可选中的子视图绑定.tag(item),明确告诉List当前行对应的数据项

修改后的完整代码:

struct ContentView: View {
    @State private var selectedItem: Obj?
    
    @State var demoData: [Obj] = [.init("Bardi"), .init("John")]
    
    var body: some View {
        List(selection: $selectedItem) {
            VStack {
                ForEach(demoData, id: \.self) { item in
                    Item(item: item)
                        .tag(item) // 绑定选中标识
                }
            }
            .listRowInsets(EdgeInsets()) // 重置行边距
        }
    }
}

struct Obj: Hashable {
    var id: UUID = .init()
    var name: String = ""
    
    init(_ name: String) {
        self.name = name
    }
}

struct Item: View {
    var item: Obj
    
    var body: some View {
        VStack {
            Text(item.name)
        }
    }
}

如果需要实现分类式列表,比如多个分组,可以给每个分类的外层容器添加标题,同时保持上述设置:

// 示例:多分类列表
List(selection: $selectedItem) {
    // 第一组
    Section("分组1") {
        VStack {
            ForEach(group1Data, id: \.self) { item in
                Item(item: item)
                    .tag(item)
            }
        }
        .listRowInsets(EdgeInsets())
    }
    
    // 第二组
    Section("分组2") {
        VStack {
            ForEach(group2Data, id: \.self) { item in
                Item(item: item)
                    .tag(item)
            }
        }
        .listRowInsets(EdgeInsets())
    }
}

这样既保留了复杂的嵌套视图结构,又能让List正常处理选中状态和键盘导航。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:24:55