Clearly, the star of this year's WWDC was the new Drag and Drop feature in iOS 11. Apple prepared a total of four (!) related sessions to introduce the API to developers.
- Session 203 - Introducing Drag and Drop
- Session 213 - Mastering Drag and Drop
- Session 223 - Drag and Drop with Collection and Table View
- Session 227 - Data Delivery with Drag and Drop
If you watch closely, you will notice that all demos shown during these sessions run exclusively on iPad. Interestingly enough, Apple seems to stay rather quiet about the fact, that the iPhone supports Drag and Drop as well (although with limits). From the docs:
All drag and drop features are available on iPad. On iPhone, drag and drop is available only within an app.
At grandcentrix, I'm currently working on an iPhone project where I need to support dragging and dropping items from one collection view to another. I don't need inter-application Drag and Drop, so in theory, it should just work if I consume the APIs just like the engineers did during the sessions, right?
Well, no. Apple basically introduced two versions of its Drag and Drop API. One is a very generic one, so that you can make any type of view (and the data going with it) draggable and droppable by attaching objects that conform to
UIInteraction and passing a delegate.
draggingView.addInteraction(UIDragInteraction(delegate: self)) dropTargetView.addInteraction(UIDropInteraction(delegate: self))
However, since you often want do drag and drop in table and collection views, a second, more higher level API was introduced. This API is a little bit limiting in terms of customization but in return, it provides some great convenience functions for dealing with index paths.
sourceCollectionView.dragDelegate = self destinationCollectionView.dropDelegate = self
In my application, I wanted to have full control over the look and feel of the interaction so I decided to go for the more generic API, even though I was dealing with two collection views. So I implemented everything exactly like they did in the sessions, I built and ran the app and... it didn't work. Well, we are still on an early beta, I thought, so maybe let's try the other API that was specifically designed for collection views. So I refactored, I built and ran the app again and... it didn't work.
I was frustrated, so I decided to download Apple's own sample project that basically replicates the code that they used in the sessions. When I opened the project, I noticed that it only targeted iPad as a platform. I quickly changed the project settings to convert it to a universal app and guess what: It worked on iPad but not on iPhone. And then, with a little help from the Apple Developer Forums, I discovered something very weird. Both APIs disable Drag and Drop on the iPhone (just on the iPhone) by default and you have to programmatically enable it.
So without further ado, here's how you get it to work. If you're using the more generic API for custom views, there's a flag on
UIDragInteraction that you have to set to
let dragInteraction = UIDragInteraction(delegate: self) dragInteraction.isEnabled = true draggingView.addInteraction(dragInteraction)
In case you're going for the table and collection view API, the property is named differently.
sourceCollectionView.dragInteractionEnabled = true
I didn't try to understand what the reasoning behind this platform dependent behavior was, but I hope that you don't waste as much time as I did when trying the shiny new APIs. In the end, it all comes back to the programmer's favorite saying: Once you do it right, it just works.