SwiftUI中如何使用onMove实现横向列表的拖拽重排序?
实现横向可拖拽重排的列表
要把纵向可拖拽的List改成横向排列并保留重排功能,你需要替换原生List为横向滚动容器,同时自定义拖拽和放置的逻辑,具体实现如下:
完整代码
import SwiftUI struct HorizontalReorderableList: View { @State private var contacts = [ "John", "Alice", "Bob", "Foo", "Bar" ] @State private var draggedItem: String? var body: some View { ScrollView(.horizontal) { LazyHStack(spacing: 16) { ForEach(contacts, id: \.self) { contact in Text(contact) .padding() .background(Color.gray.opacity(0.2)) .cornerRadius(8) .onDrag { draggedItem = contact return NSItemProvider(object: contact as NSString) } .onDrop(of: [.text], delegate: DropViewDelegate( item: contact, listData: $contacts, draggedItem: $draggedItem )) } } .padding() } } } // 处理放置逻辑的代理 struct DropViewDelegate: DropDelegate { let item: String @Binding var listData: [String] @Binding var draggedItem: String? func performDrop(info: DropInfo) -> Bool { guard let draggedItem = draggedItem, draggedItem != item else { return false } if let fromIndex = listData.firstIndex(of: draggedItem), let toIndex = listData.firstIndex(of: item) { withAnimation { listData.move(fromOffsets: IndexSet(integer: fromIndex), toOffset: toIndex > fromIndex ? toIndex + 1 : toIndex) } self.draggedItem = nil return true } return false } func dropEntered(info: DropInfo) { guard let draggedItem = draggedItem, draggedItem != item else { return } if let fromIndex = listData.firstIndex(of: draggedItem), let toIndex = listData.firstIndex(of: item) { if listData[toIndex] != draggedItem { withAnimation { listData.move(fromOffsets: IndexSet(integer: fromIndex), toOffset: toIndex > fromIndex ? toIndex + 1 : toIndex) } } } } func dropUpdated(info: DropInfo) -> DropProposal? { return DropProposal(operation: .move) } } #Preview { HorizontalReorderableList() }
关键实现说明
- 横向容器:用
ScrollView(.horizontal)提供横向滚动能力,内部配合LazyHStack(适合大量元素时提升性能)排列列表项。 - 拖拽触发:通过
onDrag手势记录当前被拖拽的元素,并提供拖拽数据。 - 放置处理:自定义
DropViewDelegate监听拖拽进入、更新和完成事件,调用move(fromOffsets:toOffset:)调整数组顺序,同时添加动画让重排过程更流畅。
内容的提问来源于stack exchange,提问作者Nicolas Gimelli
相关产品推荐
相关产品推荐

