Reputation: 314
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!
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
}
}
Upvotes: 3
Views: 1680
Reputation: 32694
Updating for those that might find this issue.
I learned that the reason for not providing the data during the dragEntered/dragUpdated is that the user might not have provided consent, so the drag have just accidentally entered your app.
So this is why it is not possible to get this data.
For my in-app transfer, I ended up using a side communications channel, it is not great, but I only needed this for a preview.
Upvotes: 0