Drag & Drop UICollectionView проблема повторного использования ячеек - PullRequest
3 голосов
/ 01 марта 2020

Итак, я реализовал перетаскивание для моего UICollectionView следующим образом:

func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
        guard shouldAllowDragForIndexPath?(indexPath) == true else { return [] }
        guard let cell = collectionView.cellForItem(at: indexPath)?.toImage() else {
            return []
        }
        let provider = NSItemProvider(object: cell)
        let item = UIDragItem(itemProvider: provider)
        item.localObject = data[indexPath.row]

        return [item]
    }

    func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
        guard
            let item = coordinator.items.first?.dragItem,
            let sourceIndexPath = coordinator.items.first?.sourceIndexPath,
            let destinationIndexPath = coordinator.destinationIndexPath,
            let entity = item.localObject as? T
            else {
                return
        }
        collectionView.performBatchUpdates({ [unowned self] in
            dropEntityAtIndexPath?(entity, destinationIndexPath)
            self.collectionView.deleteItems(at: [sourceIndexPath])
            self.collectionView.insertItems(at: [destinationIndexPath])
        }, completion: nil)
        coordinator.drop(item, toItemAt: destinationIndexPath)
        item.localObject = nil
    }

    func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
        if
            session.localDragSession != nil,
            let path = destinationIndexPath,
            shouldAllowDropForIndexPath?(path) == true {
            return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
        } else {
            return UICollectionViewDropProposal(operation: .forbidden)
        }
    }

Все работает, но я заметил странное поведение при повторном использовании ячейки. Вот видео: ссылка

Таким образом, это происходит только после перетаскивания ячеек, также кажется, что есть какое-то серое наложение, но я не вижу его в отладчике представления. Кроме того, я попытался установить imageView.image = nil в моей клетке prepareForReuse, но это не помогло. Буду очень признателен, если кто-нибудь поможет мне это исправить. Спасибо.

Редактировать1: Код в cellForItemAt:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(for: indexPath, cellType: PhotoCollectionViewCell.self)
        let container = data[indexPath.row].postContainer,
        let post = container.postMedia.first
        let isCarousel = container.isCarousel
        let isVideo = post.isVideo
        let _isSelected = isSelected?(indexPath) ?? false
        let url = post.thumbURL?.toURL()
        let isScheduled = container.schedulerFor != nil
        let fromInstagram = false

        cell.configure(url: url, isSelected: _isSelected, isVideo: isVideo, isCarousel: isCarousel, isScheduled: isScheduled, fromInstagram: fromInstagram)

    return cell
}

Редактировать 2 Функция конфигурации ячейки:

func configure(url: URL?, isSelected: Bool = false, isVideo: Bool = false, isCarousel: Bool = false, isScheduled: Bool = false, fromInstagram: Bool = false) {
        checkmarkImageView.isHidden = !isSelected
        selectionOverlay.isHidden = !isSelected
        isVideoImageView.isHidden = !isVideo
        carouselImageView.isHidden = !isCarousel
        cornerImageView.image = isScheduled ? R.image.cyanCorner() : R.image.grayCorner()
        instagramImageView.isHidden = !fromInstagram
        cornerImageView.isHidden = fromInstagram
        url.map(imageView.setImage(with:))
    }

1 Ответ

0 голосов
/ 06 марта 2020

Я думаю, что проблема не в повторном использовании ячейки, а в неправильном обновлении модели. item.localData должно быть обновлено должным образом, когда движение закончено.

Это означает, что вы должны обновить объект вашей модели данных перед вызовом UICollectionView update.

Вот пример для UICollectionViewDelegate, но на самом деле важна только эта строка:

// YOUR MODEL OBJECT is expected to be a list-like data structure
YOUR_MODEL_OBJECT.insert(YOUR_MODEL_OBJECT.remove(at: sourceIndex), at: destinationIndex)

Как это работает для UICollectionViewDelegate

func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    guard destinationIndexPath != sourceIndexPath else { return }
    // YOUR MODEL OBJECT is expected to be a list-like data structure
    YOUR_MODEL_OBJECT.insert(YOUR_MODEL_OBJECT.remove(at: sourceIndex), at: destinationIndex)
}
...