Validate drag operations with Transferable

Let's say I want to build a simple photo management app on Mac or iPad with Swift UI. This app has multi-window support. My photos are organized inside albums. I should be able to drag photos between windows from one album to another.

I struggle to get this working properly with Swift UI. Writing modern code I would like to use Transferable. Let's say my photos are not real files. So I can't use a FileRepresentation. Instead I use CodableRepresentation and encode an identifier. This identifier is later used to drive the move operation between folders.

I ran into some limitations here

  1. Transferable seems to be meant for copy-like Drag & Drop operations. I have no possible to get a "move" cursor on macOS (it's always the copy cursor with the green + sign). Also the API reads like it is about importing/exporting – not moving.
  2. When using dropDestination on ForEach, I completely lack the possibility to deny a drop (e.g. when a photo is already part of the album).
  3. I'd like to have modifier key to switch between copying and moving.
  4. Sometimes a drop should be redirected to a different index. How to do that?

Is there any chance to do this with Transferable? It even doesn't seem to be easy with NSItemProvider and onDrop/onDrag? Or should we still use a plain old UICollectionView/NSCollectionView, if we want to have more sophisticated control over drag/drop validation?

First I would suggest you review Adopting drag and drop using SwiftUI sample project and article. It covers most of the questions you have.

You wrote:

Sometimes a drop should be redirected to a different index. How to do that?

This depends on the context of the drop. For example, a dropDestination(for:action:) on a Table row would provide you the offset relative to the view’s underlying collection of data and you could use that to determine the appropriate index.

You wrote:

I'd like to have modifier key to switch between copying and moving.

This is currently not supported with Transferable. If you'd like us to consider adding the necessary functionality, please file an enhancement request using Feedback Assistant. Once you file the request, please post the FB number here.

If you're not familiar with how to file enhancement requests, take a look at Bug Reporting: How and Why?

Thanks for your response!

This depends on the context of the drop. For example, a dropDestination(for:action:) on a Table row would provide you the offset relative to the view’s underlying collection of data and you could use that to determine the appropriate index.

I actually meant the functionality of -[NSOutlineView setDropItem:dropChildIndex:] where I can re-target the drop to another list item or making an ordered insertion to an unordered insertion.

This is currently not supported with Transferable.

Okay, thanks – I'll file a feedback.

I wonder about the best workaround. Using onMove is not an option, because I want to be able to move items across multiple windows. Also it doesn't support move across List sections.

The only option I see is to use onDrop and changing the drop icon using the DropDelegate. But it seems this won't display the blue drop indicator on macOS (while dropDestination does this).

@hydrixos Their isn't a direct 1-1 mapping of that in SwiftUI. You'll need to add the dropDestination(for:action:isTargeted:) modifier to the view that should handle the dropped content. the isTarget closure is called when a drag and drop operation enters or exits the drop target area. so you could use that to provide a visual indication when a drop enters a view that is outside the scope of the drop target.

Okay, thanks for pointing out!

But in this case I would have to use custom UI for drawing the indicator? It's not possible to trigger the standard indicators of macOS?

Validate drag operations with Transferable
 
 
Q