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

SwiftUI中如何拖拽重排List内DisclosureGroup的分区与条目

SwiftUI实现带DisclosureGroup的List分区与条目拖拽重排

要实现分区(Section)和DisclosureGroup内部条目的拖拽重排,无需修改List和DisclosureGroup本身,只需通过SwiftUI的拖拽修饰符和编辑模式配合即可解决,以下是具体实现方案:

1. 定义数据结构

首先创建可观察的分区数据模型,包含分区标题和内部条目:

import SwiftUI

struct SectionItem: Identifiable {
    let id = UUID()
    var title: String
    var items: [String]
}

class DragSortViewModel: ObservableObject {
    @Published var sections: [SectionItem] = [
        SectionItem(title: "分区1", items: ["条目1-1", "条目1-2", "条目1-3"]),
        SectionItem(title: "分区2", items: ["条目2-1", "条目2-2"]),
        SectionItem(title: "分区3", items: ["条目3-1"])
    ]
}

2. 实现拖拽重排视图

核心逻辑说明:

  • 分区重排:通过ForEach($sections)绑定分区数据,给DisclosureGroup添加contentShape确保整个标签区域可响应拖拽,配合onDrag提供拖拽标识,最后在分区的ForEach上添加onMove处理分区数组的移动。
  • 内部条目重排:在DisclosureGroup内部的条目ForEach上添加onMove,直接操作对应分区的条目数组即可。

完整视图代码:

struct DragSortView: View {
    @StateObject private var viewModel = DragSortViewModel()
    @Environment(\.editMode) private var editMode
    
    var body: some View {
        NavigationStack {
            List {
                // 遍历分区,处理分区拖拽重排
                ForEach($viewModel.sections) { $section in
                    Section {
                        DisclosureGroup {
                            // 遍历内部条目,处理条目拖拽重排
                            ForEach($section.items, id: \.self) { $item in
                                Text(item)
                            }
                            .onMove { indices, newOffset in
                                section.items.move(fromOffsets: indices, toOffset: newOffset)
                            }
                        } label: {
                            Text(section.title)
                                // 长按标签快速进入编辑模式(可选)
                                .gesture(
                                    LongPressGesture()
                                        .onEnded { _ in
                                            editMode?.wrappedValue = .active
                                        }
                                )
                        }
                        // 让整个DisclosureGroup标签区域都能响应拖拽手势
                        .contentShape(Rectangle())
                        // 提供拖拽的唯一标识
                        .onDrag {
                            NSItemProvider(object: section.id.uuidString as NSString)
                        }
                    }
                }
                .onMove { indices, newOffset in
                    viewModel.sections.move(fromOffsets: indices, toOffset: newOffset)
                }
            }
            .navigationTitle("拖拽重排示例")
            .toolbar {
                // 系统默认编辑按钮,开启后显示拖拽图标
                EditButton()
            }
        }
    }
}

关键注意点

  • contentShape(Rectangle())是核心:默认情况下DisclosureGroup的标签只有文字区域可交互,添加这个修饰符后,整个标签单元格都会响应拖拽手势,解决之前拖拽触发失败的问题。
  • 编辑模式依赖:SwiftUI的onMove默认需要在编辑模式下生效,你可以通过EditButton手动开启,或者通过长按手势自动触发编辑模式(代码中已实现)。
  • 数据绑定:使用$绑定数据,确保拖拽后数据实时更新,视图自动刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 10:52:17