获取拖动预览的帧

Posted

技术标签:

【中文标题】获取拖动预览的帧【英文标题】:Get frame of Drag preview 【发布时间】:2018-12-03 20:10:00 【问题描述】:

我正在使用 ios 11 中引入的新 Apple API 在 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 之类的操作,但这种方法并不准确:看起来预览与触摸位置有一些偏移。

【问题讨论】:

看看这里,也许有帮助:hackernoon.com/… 已经看过了,没有任何帮助:( @Andrey Gordeev 我现在面临着确切的问题,运气好吗?? 【参考方案1】:

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

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

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

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

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

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

我希望这会有所帮助。

【讨论】:

【参考方案2】:

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

你可以在这里看到一个工作示例:https://github.com/zjfjack/JZCalendarWeekView/blob/master/JZCalendarWeekView/JZLongPressWeekView.swift#L385

【讨论】:

【参考方案3】:

我也面临同样的问题。我浏览了 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

【讨论】:

以上是关于获取拖动预览的帧的主要内容,如果未能解决你的问题,请参考以下文章

使用 ThreeSixty 创建可拖动的 360 度全景图片预览效果

UIDragInteractionDelegate:如何在dragInteraction返回的拖动预览中显示透明部分(_:previewForLifting:session:)

js实现移动端图片预览:手势缩放, 手势拖动,双击放大...

Android 实现仿微信朋友圈九宫格图片+NineGridView+ImageWatcher(图片查看:1.预览,2.拖动,3.放大,4.左右滑动,5.长按保存到手机)的功能

vue 快速给图片添加,点击旋转、放大、缩小、拖动的效果

从给定位置拖动图钉