Я пытаюсь реализовать Drag & Drop для моего UICollectionViews (а также хочу узнать о UICollectionViewLayout). Я реализовал методы dragDelegate/dropDelegate для представления коллекции, и теперь я могу перетаскивать ячейки.
Я также установил намерение предложения перетаскивания на .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]
}
}
Это некрасиво, это не оптимально, это просто для проверки. Моя проблема теперь в том, что он вылетает, когда я перетаскиваю ячейку и перемещаю ее:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView received layout attributes for a cell with an index path that does not exist: {length = 2, path = 0 - 0}'
Я понятия не имею, что здесь происходит и почему. Что-то меняется, когда ячейки пытаются переместиться (чтобы освободить место для перетаскиваемой ячейки, которая парит выше).
Было бы здорово, если бы кто-нибудь мог сказать мне, о чем мне нужно позаботиться, когда я хочу поддерживать перетаскивание ячеек с помощью моего настраиваемого макета. Я наблюдал почти все сеансы WWDC на Drag & Drop, но не могу найти для этого решения.
Спасибо!
Обновлено:
Я кое-что узнал. Внутри layoutAttributesForElements(in:) я постоянно распечатываю все видимые пути IndexPath в 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 в элементе 1. Почему? И что я могу сделать с этой информацией?
Я видел это, но, к сожалению, это другая ситуация и здесь не применима
IGListKit в какой-то момент также сообщал об этой ошибке: github.com/Instagram/IGListKit/issues/813
Да, я видел это, но, к сожалению, это тоже не связано.





Вы пробовали один из этих обходных путей: stackoverflow.com/q/27515673/1506363