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

SwiftUI中如何让List将DisclosureGroup整体视为单个列表项?

SwiftUI List中DisclosureGroup的单元格识别问题

在使用SwiftUI的List组件时,若在列表项中嵌入DisclosureGroup,List会将DisclosureGroup的展开内容识别为独立的列表单元格,这会导致onMove和onDelete功能出现异常——操作时会误选中展开内容而非整个组,引发无意义的未定义行为。我们需要让整个DisclosureGroup组被视为单个列表元素。

示例代码

struct ContentView: View {
    @State var items: [Int] = [0, 1, 2, 3]

    var body: some View {
        List {
            ForEach($items, id: \.self) { $item in
                DisclosureGroupView()
            }
            .onDelete { indexSet in
                items.remove(atOffsets: indexSet)
            }
            .onMove { indices, newOffset in
                items.move(fromOffsets: indices, toOffset: newOffset)
            }
        }
    }
}

struct DisclosureGroupView: View {
    var body: some View {
        DisclosureGroup {
            VStack(spacing: 8) {
                Text("Test text")
                Text("Test text")
                Text("Test text")
            }
        } label: {
            HStack {
                Text("Tap to Expand")
                Spacer()
                Image(systemName: "ellipsis")
            }
        }
    }
}

问题演示

问题演示

可以看到,删除/重排操作会误作用于DisclosureGroup的展开内容,而非整个组,这不符合预期。

解决方案

方法一:使用.disclosureGroupStyle(.header)调整布局逻辑

通过指定DisclosureGroup的样式为.header,让展开内容隶属于当前单元格,而非生成新的列表项,同时配合listRowInsets消除额外间距:

struct DisclosureGroupView: View {
    var body: some View {
        DisclosureGroup {
            VStack(spacing: 8) {
                Text("Test text")
                Text("Test text")
                Text("Test text")
            }
            .padding(.leading) // 手动模拟默认展开内容的缩进效果
        } label: {
            HStack {
                Text("Tap to Expand")
                Spacer()
                Image(systemName: "ellipsis")
            }
        }
        .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
        .disclosureGroupStyle(.header)
    }
}

方法二:用容器视图包裹DisclosureGroup

将DisclosureGroup放入VStack或Group中,强制List将整个结构识别为单个单元格:

struct DisclosureGroupView: View {
    var body: some View {
        VStack(spacing: 0) {
            DisclosureGroup {
                VStack(spacing: 8) {
                    Text("Test text")
                    Text("Test text")
                    Text("Test text")
                }
                .padding(.leading)
            } label: {
                HStack {
                    Text("Tap to Expand")
                    Spacer()
                    Image(systemName: "ellipsis")
                }
            }
        }
        .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
    }
}

关键说明

  • listRowInsets用于消除容器与List单元格边缘的额外空白;
  • 手动添加.padding(.leading)是为了还原默认展开内容的缩进视觉效果,可根据需求调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 22:52:48