Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get frame of Drag preview

I'm implementing drag-n-drop on UICollectionView using a new Apple's API introduced in iOS 11.

What I need is to get a frame of drag preview (see below, red rectangle) iOS Drag and drop on UICollectionView

I tried to get drag's location:

extension ViewController: UICollectionViewDropDelegate {
    func collectionView(_ collectionView: UICollectionView, 
         dropSessionDidUpdate session: UIDropSession, 
         withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
        let location = session.location(in: collectionView)
    }

but it represents my finger's location only. I need to get the entire frame or, at least, it's origin.

I also tried to store y position of touch in my cell and then do something like dragLocation.y - touchLocationInCell.y, but this approach is not accurate: looks like the preview gets some offset from the touch location.

like image 206
Andrey Gordeev Avatar asked Jun 25 '18 09:06

Andrey Gordeev


2 Answers

I have worked on similar functionality and can share some details. To be short, it seems that there is no option that allows position tracking of preview view.

From my perspective, I would not rely on the frame of the preview view. There are some cases when system could make preview view smaller or bigger than original view. For instance, it could happen when initial dragged view size is bigger than it's super view size. In this case system will make preview view smaller in order to bring more visibility about content that is being dragged. And this behavior is not predictable, system could apply such transformation based on some internal logic.

I think the way it works is because drag and drop engine allows to move items not only inside one specific app but between other apps. Since that, drag and drop engine should be a separate system process that handles all drag and drop operations including preview sizing and position.

During drag operation, system creates either original view snapshot or snapshot of the view that was returned from previewProvider of UIDragItem.

Then it creates container view (instance of private UIPortalView class with CAPortalLayer underneath), installs snapshot into this container and displays container view. Since that moment preview view position is handled by system and there is no public API to access this view.

The only possible way to track drag position is to use location(in view: UIView) function of UIDragDropSession protocol.

I hope this helps.

like image 165
Alex D. Avatar answered Nov 09 '22 01:11

Alex D.


I am facing the same issue (trying to drag/drop a UICollectionView calendar event cell) and I've come to the conclusion (as did Alex D.) that the iOS 11 provided "preview" view cannot solve this problem. However, I did find a decent alternative solution, which is basically to create your own preview view from a UICollectionViewCell.snapshot. Then you can drag that view around and you'll have access to its position, and once the user "drops" the view, create the new cell based on the custom preview view's position and remove the custom preview view.

You can see a working example of this here: https://github.com/zjfjack/JZCalendarWeekView/blob/master/JZCalendarWeekView/JZLongPressWeekView.swift#L385

like image 45
Ricky Padilla Avatar answered Nov 09 '22 01:11

Ricky Padilla