获取拖动预览的帧

时间:2018-06-25 09:32:09

标签: ios swift drag-and-drop uicollectionview

我正在使用iOS 11中引入的新的Apple API在UICollectionView上实现拖放。

我需要得到一个拖动预览框架(请参见下面的红色矩形) iOS Drag and drop on UICollectionView

我试图获取拖动的位置:

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

但是它仅代表我手指的位置。我需要获取整个框架,或者至少是原始框架。

我还尝试将y的触摸位置存储在我的单元格中,然后执行类似dragLocation.y - touchLocationInCell.y的操作,但是这种方法不准确:看起来预览与触摸位置有些偏移。 / p>

3 个答案:

答案 0 :(得分:2)

我已经研究过类似的功能,并且可以分享一些细节。简而言之,似乎没有允许跟踪预览视图位置的选项。

从我的角度来看,我不会依赖预览视图的框架。在某些情况下,系统可能会使预览视图小于或大于原始视图。例如,当初始拖动的视图大小大于其超级视图大小时,可能会发生这种情况。在这种情况下,系统将使预览视图更小,以便为正在拖动的内容带来更多可见性。而且这种行为是不可预测的,系统可以基于一些内部逻辑来应用这种转换。

我认为它的工作方式是因为拖放引擎不仅允许在一个特定应用程序内移动项目,还可以在其他应用程序之间移动项目。从那以后,拖放引擎应该是一个单独的系统进程,处理所有拖放操作,包括预览大小和位置。

在拖动操作期间,系统会创建原始视图快照或从UIDragItem的previewProvider返回的视图的快照。

然后,它创建容器视图(私有UIPortalView类的实例,其下有CAPortalLayer),将快照安装到该容器中并显示容器视图。由于此刻预览视图的位置由系统处理,因此没有公共API可以访问该视图。

跟踪拖动位置的唯一可能方法是使用location(in view: UIView)协议的UIDragDropSession功能。

我希望这会有所帮助。

答案 1 :(得分:0)

我面临着相同的问题(试图拖放UICollectionView日历事件单元格),并且得出的结论(Alex D.也是如此)是iOS 11提供的“预览”视图无法解决此问题。但是,我确实找到了一个不错的替代解决方案,该解决方案基本上是从UICollectionViewCell.snapshot创建您自己的预览视图。然后,您可以拖动该视图,并可以访问其位置,一旦用户“放下”该视图,请根据自定义预览视图的位置创建新的单元格,然后删除自定义预览视图。

您可以在此处看到一个有效的示例:https://github.com/zjfjack/JZCalendarWeekView/blob/master/JZCalendarWeekView/JZLongPressWeekView.swift#L385

答案 2 :(得分:0)

我面临着同样的问题。我遍历了Apple提供的所有代码,但是找不到任何可以在预览框中提供信息的内容。我最终要做的是存储单元的初始位置,然后通过初始触摸和最终触摸的位移来移动原点。像这样

func finalFrame(at location: CGPoint) -> CGRect {
    var displacement: CGPoint = CGPoint(x: 0, y: 0)
    displacement.x = location.x - initialTapLocation.x
    displacement.y = location.y - initialTapLocation.y

    var newFrame = initialCellFrame
    newFrame.origin.x += displacement.x
    newFrame.origin.y += displacement.y

    return newFrame
}

不是理想的解决方案,特别是用于带有缩放动画的自定义预览,但是我希望这会有所帮助。您可以从session.location:in获得的位置,并且我将初始位置存储在自定义协调器类型中,但是您可以为此使用本地对象或上下文。

您可以在

中获取初始位置和框架

collectionView:dragSessionWillBegin

collectionView:itemsForBeginning:at

let location = session.location(in: collectionView) //store this

//if using the second method, it provides the indexpath, so no need to look for it
let indexPath = collectionView.indexPathForItem(at: location)

let cell = collectionView.cellForItem(at: indexPath)
cell.frame // store this also