首页 > 解决方案 > `dropSessionDidUpdate` 中的 UICollectionViewDropDelegate 错误的目标索引路径

问题描述

我正在尝试在这个狭长的集合视图中实现拖放: UICollectionView

它具有水平布局,具有不同大小的单元格和部分。

拖动交互效果很好,但我注意到UICollectionViewDropDelegate中的一个问题:

func collectionView(
    _ collectionView: UICollectionView,
    dropSessionDidUpdate session: UIDropSession,
    withDestinationIndexPath destinationIndexPath: IndexPath?)
    -> UICollectionViewDropProposal {

    if let destination = destinationIndexPath {
        print(destination) // Prints WRONG index path!!!
        return UICollectionViewDropProposal(
            operation: .move, intent: .insertAtDestinationIndexPath
        )
    }

    return UICollectionViewDropProposal(
        operation: .cancel, intent: .unspecified
    )
}

错误的目标索引路径传递给collectionView(_:dropSessionDidUpdate:withDestinationIndexPath:)
因此,我无法正确确定该部分并确定该部分是否可用。

标签: iosswiftuicollectionviewdrag-and-dropuikit

解决方案


所以,这是 UIKit 的一个 bug。正确的目的索引路径可以计算如下:

func collectionView(
    _ collectionView: UICollectionView,
    dropSessionDidUpdate session: UIDropSession,
    withDestinationIndexPath destinationIndexPath: IndexPath?)
    -> UICollectionViewDropProposal {

    // Calculating location in view
    let location = session.location(in: collectionView)
    var correctDestination: IndexPath?

    // Calculate index inside performUsingPresentationValues
    collectionView.performUsingPresentationValues {
        correctDestination = collectionView.indexPathForItem(at: location)
    }

    guard let destination = correctDestination else {
        return UICollectionViewDropProposal(
            operation: .cancel, intent: .unspecified
        )
    }

    // check destination 
    // ...
}

为了修复这个错误,首先,我尝试使用 和 的location(in:)组合indexPathForItem(at:)。生成的索引路径等于destinationIndexPath委托方法提供的索引路径。为什么?UIDataSourceTranslating引起了我的注意。这是一个协议,允许集合和表格视图显示用于拖放的占位符单元格,而无需更改实际数据源。当拖放交互结束时,占位符很容易被删除。所以,我做了一个假设

  1. destinationIndexPath是在帮助下计算的indexPathForItem(at:)
  2. 它忽略了由 UIDataSourceTranslating 创建的占位符,这是一个错误

然后我尝试换indexPathForItem(at:)performUsingPresentationValues(_:),收到的索引路径是正确的!


推荐阅读