Я пытаюсь реализовать Drag & Drop для своих UICollectionViews
(а также хочу узнать о UICollectionViewLayout
s).Я реализовал 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]
}
}
Это не красиво, это не оптимально, это просто проверить вещи .Моя проблема сейчас заключается в том, что он падает, когда я перетаскиваю ячейку и перемещаю ее:
Завершение приложения из-за необработанного исключения «NSInternalInconsistencyException», причина: «UICollectionView получил атрибуты макета для ячейки с индексным путемэтого не существует: {length = 2, path = 0 - 0} '
Я понятия не имею, что здесь происходит и почему.Есть кое-что, что меняется, когда ячейки пытаются двигаться (чтобы освободить место для перетаскиваемой ячейки, которая зависает над ней).
Было бы замечательно, если бы кто-то мог сказать мне, что мне нужно позаботиться, когда я хочу поддержатьперетаскивая ячейки с моим собственным макетом.Я смотрел почти все сессии WWDC на Drag & Drop, но я не могу найти решение для этого.
Спасибо!
ОБНОВЛЕНИЕ: Я кое-что узнал.Внутри 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 в пункте 1. Почему это так?И что я могу сделать с этой информацией?