使用IOS 11拖放功能拖动单元格时,UICollectionViewFlowLayout中究竟发生了什么?

Qua*_*ntm 7 drag-and-drop ios uicollectionview uicollectionviewlayout swift

我正在尝试为我实现拖放UICollectionViews(我也想了解UICollectionViewLayouts).我实现了dragDelegate/dropDelegate集合视图的方法,现在我可以拖动单元格了.

我还设置了drop的意图.insertAtDestinationIndexPath,以便单元格移动到拖动单元格的位置(因此当将拖动的单元格悬停在其上时,布局会发生变化).

这与之完美配合UICollectionViewFlowLayout.但是,我正在使用IGListKit它基本上为集合视图中的每个单元格使用一个部分.部分通常总是在新行上渲染,但我希望在同一行上有多个部分(=单元格).这就是我将布局子类化的原因:

class CustomFlowLayout: UICollectionViewFlowLayout {

override var collectionViewContentSize: CGSize {
    return CGSize(width: contentWidth, height: contentHeight)
}

fileprivate var contentHeight: CGFloat = 0

fileprivate var contentWidth: CGFloat {
    guard let collectionView = collectionView else {
        return 0
    }
    let insets = collectionView.contentInset
    return collectionView.bounds.width - (insets.left + insets.right)
}

var cachedAttribtues = [UICollectionViewLayoutAttributes]()

override func prepare() {
    super.prepare()
    cachedAttribtues = []
    guard let collectionView = collectionView else { return }
    let sectionCount = collectionView.numberOfSections

    var columnWidth = contentWidth / 2 - 5

    var yOffset: CGFloat = 0
    var column = 0

    for section in 0..<sectionCount {
        let indexPath = IndexPath(item: 0, section: section)

        let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
        attributes.frame = CGRect(x: CGFloat(column) * columnWidth, y: yOffset, width: columnWidth, height: 150)

        yOffset += CGFloat(column) * 200
        column = (column + 1) % 2


        cachedAttribtues.append(attributes)
    }

}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()

    for attributes in cachedAttribtues {
        if attributes.frame.intersects(rect) {
            visibleLayoutAttributes.append(attributes)
        }
    }

    return visibleLayoutAttributes
}

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    return cachedAttribtues[indexPath.section]
}
}
Run Code Online (Sandbox Code Playgroud)

它不漂亮,它不是最佳的,它只是为了测试.我现在的问题是当我拖动一个单元格并移动它时它会崩溃:

由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'UICollectionView接收到具有不存在的索引路径的单元格的布局属性:{length = 2,path = 0 - 0}'

我完全不知道这里发生了什么以及为什么.当细胞试图移动时(对于悬停在上方的拖曳细胞而言),会发生一些变化.

如果有人可以告诉我当我想支持使用我的自定义布局拖动单元格时需要处理什么,这将是非常棒的.我几乎看过所有关于Drag&Drop的WWDC会议,但我找不到解决方案.

谢谢!

更新: 我发现了一些东西.在里面,layoutAttributesForElements(in:)我不断打印出所有可见的IndexPaths UICollectionView.一开始,它看起来像这样:

[[0,0],[2,0],[1,0],[3,0]]

在应用程序崩溃之前,它看起来像这样:

[[0,1],[2,0],[0,0],[3,0]]

所以我认为问题是这样的:在prepare(),我UICollectionViewLayoutAttributes为索引0处的所有部分创建.所以当我传递给定的属性时,CGRect它将返回section 1, item 0,但这不存在,因为它以某种方式成为section 0, item 1(我认为) .

所以系统想要在第0项的第0项中放置一个单元格.为什么会这样?我能用这些信息做些什么?