I’ve got a simple, single-column, view-based NSTableView with items in it that can be dragged to reorder them. During drag and drop, I’d like to make it so that a gap for the item-to-be-dropped opens up at the location under the mouse. GarageBand does something like this when you drag to reorder tracks (video here: http://www.screencast.com/t/OmUVHcCNSl). As far as I can tell, there’s no built in support for this in NSTableView.
Has anyone else tried to add this behavior to NSTableView and found a good solution? I’ve thought of and tried a couple approaches without much success. My first thought was to double the height of the row under the mouse during a drag by sending -noteHeightOfRowsWithIndexesChanged: in my data source’s -tableView:validateDrop:... method, then returning twice the normal height in -tableView:heightOfRow:. Unfortunately, best I can tell, NSTableView doesn’t update its layout during drag and drop, so despite calling noteHeightOfRowsWithIndexesChanged:, the row height isn’t actually updated.
Note that I’m using a view-based NSTableView, but my rows are not so complex that I couldn’t move to a cell-based table view if doing so helped accomplish this. I’m aware of the easy, built-in ability to animate a gap for the dropped item after a drag is complete. I’m looking for a way to open a gap while the drag is in progress. Also, this is for an app to be sold in the Mac App Store, so it must not use private API.
EDIT: I’ve just filed an enhancement request with Apple requesting built in support for this behavior: http://openradar.appspot.com/12662624. Dupe if you’d like to see it too. Update: The enhancement I requested was implemented in OS X 10.9 Mavericks, and this behavior is now available using NSTableView API. See NSTableViewDraggingDestinationFeedbackStyleGap.
Note: The behavior this question and answer describes are now available using built in API in NSTableView on OS X 10.9 Mavericks and later. See NSTableViewDraggingDestinationFeedbackStyleGap.
This answer may still be useful if this behavior is needed in an app targeting OS X 10.8 or earlier.
Original answer below:
I’ve implemented this now. My basic approach looks like this:
// In my delegate and data source:
Note that this is simplified code, not a verbatim copy/paste from my program. I actually ended up making this all contained within an NSTableView subclass that uses proxy delegate and data source objects so the code in data source/delegate methods above is actually inside the proxies’ intercept of the calls to the real delegate and data source. That way, the real data source and delegate don’t have to do anything special to get the gap opening behavior. Also, there’s sometimes a little flakiness with the table view animations, and this doesn’t work for drags above the first row (no gap is opened since there’s no row to make taller). All in all, despite the room for further improvement, this approach works reasonably well.
I’d still like to try a similar approach, but insert a blank row (as Caleb suggested) instead of changing the row height.