我正在开发一个 SwiftUI 项目,其中有一个使用列表视图显示的项目列表。我想提供两个功能:列表中的项目替换和项目重新排序。
我正在寻求社区关于如何有效结合这两种功能的意见。如何同时使用 onDrag 和 onDrop 修饰符在列表中启用项目替换和重新排序?
任何见解、建议或代码示例将不胜感激。
import SwiftUI
struct ContentView: View {
@State private var items = ["Item 1", "Item 2", "Item 3", "Item 4"]
@State private var highlightedIndex: Int?
var body: some View {
List {
ForEach(items.indices, id: \.self) { index in
let item = items[index]
HStack {
Text(item)
.foregroundColor(highlightedIndex == index ? .red : .primary)
Spacer()
}
.onDrag {
NSItemProvider(object: NSString(string: "\(index)"))
}
.onDrop(of: [.text], delegate: MyDropDelegate(itemIndex: index, items: $items, highlightedIndex: $highlightedIndex))
}
.onMoveCommand(perform: moveItem)
}
}
func moveItem(_ direction: MoveCommandDirection) {
guard let sourceIndex = items.firstIndex(where: { $0 == items[highlightedIndex ?? 0] }) else {
return
}
var destinationIndex: Int
switch direction {
case .up:
destinationIndex = sourceIndex - 1
if destinationIndex < 0 {
destinationIndex = items.count - 1
}
case .down:
destinationIndex = sourceIndex + 1
if destinationIndex >= items.count {
destinationIndex = 0
}
@unknown default:
return
}
items.move(fromOffsets: IndexSet(integer: sourceIndex), toOffset: destinationIndex)
highlightedIndex = destinationIndex
}
}
struct MyDropDelegate: DropDelegate {
let itemIndex: Int
@Binding var items: [String]
@Binding var highlightedIndex: Int?
func performDrop(info: DropInfo) -> Bool {
let item = info.itemProviders(for: ["public.text"]).first
item?.loadObject(ofClass: NSString.self) { item, _ in
if let itemString = item as? NSString {
let intValue = itemString.intValue
let swiftInt = Int(intValue)
let sourceIndex = swiftInt
let droppedItem = items[sourceIndex]
if let highlightedIndex = highlightedIndex {
items[highlightedIndex] = droppedItem
}
}
}
return true
}
func validateDrop(info: DropInfo) -> Bool {
highlightedIndex = itemIndex
return info.hasItemsConforming(to: [.text])
}
func dropEntered(info: DropInfo) {
highlightedIndex = itemIndex
}
func dropExited(info: DropInfo) {
highlightedIndex = nil
}
}
不要使用 .onDrag,而是使用 .itemProvider。 经过数小时的尝试和错误后,这似乎就是魔法。