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
相关产品推荐
相关产品推荐

