Что именно происходит в UICollectionViewFlowLayout при перетаскивании ячейки с помощью функции перетаскивания IOS 11?

Я пытаюсь реализовать 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. Почему? И что я могу сделать с этой информацией?

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

Nirav Bhatt 18.06.2018 09:44

Я видел это, но, к сожалению, это другая ситуация и здесь не применима

Quantm 18.06.2018 12:30

IGListKit в какой-то момент также сообщал об этой ошибке: github.com/Instagram/IGListKit/issues/813

Nirav Bhatt 18.06.2018 13:50

Да, я видел это, но, к сожалению, это тоже не связано.

Quantm 18.06.2018 13:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
4
614
0

Другие вопросы по теме