I am dragging and dropping views using a DropDelegate in SwiftUI. I'm successfully wrapping my data in an NSItemProvider using the .onDrag View Modifier, and I even have .onDrop working if I am able to have my drop data be one of the stored properties of my DropDelegate.
I'm trying to allow for decoding my drop data using the provided DropInfo. I update my view in the dropEntered(info:)
delegate method, so that the user can have a preview of their drop before it occurs. When I write
info.itemProviders.first?.loadObject(...) { reading, error in
...
}
The completion handler is not called. If I were to instead write this closure in the performDrop(info:)
delegate method, the completion handler would be called. Why is the completion handler only called in performDrop(info:)
? Is there a way to have drag & drop previews while performing the necessary changes in real time while not having the data model changed in dropEntered(info:)
?
I don't love that I edit my data model in dropEntered(info:)
, and I haven't gotten to how it would work if the user were to cancel the drag and drop somehow... Perhaps there's a better way to go about this that will allow me to edit my data model in performDrop(info:)
?
Thank you!
Edit
Here's the code to reproduce the bug:
struct ReorderableForEach<Content: View, Item: Identifiable>: View {
let items: [Item]
let content: (Item) -> Content
var body: some View {
ForEach(items) { item in
content(item)
.onDrag {
return NSItemProvider(object: "\(item.id)" as NSString)
}
.onDrop(
of: [.text],
delegate: DragRelocateDelegate()
)
}
}
}
struct DragRelocateDelegate: DropDelegate {
func dropEntered(info: DropInfo) {
let _ = info.itemProviders(for: [.text]).first?.loadObject(ofClass: String.self) { item, error in
print("dropEntered: \(item)") // Won't trigger this
}
}
func performDrop(info: DropInfo) -> Bool {
let _ = info.itemProviders(for: [.text]).first?.loadObject(ofClass: String.self) { item, error in
print("performDrop: \(item)") // Will trigger this
}
return true
}
}