Сбой анимации при удалении элемента UICollectionViewDiffableDataSource из контекстного меню

Я принял новый UICollectionViewDiffableDataSource. Я применяю снимок источника данных каждый раз, когда удаляю элемент:

var snapshot = NSDiffableDataSourceSnapshot<Int, Item>()
snapshot.appendSections([0])
snapshot.appendItems(items)
apply(snapshot, animatingDifferences: true)

Удаление предлагается с помощью встроенной опции конфигурации представления коллекции:

func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
    guard let item = dataSource.itemIdentifier(for: indexPath) else {
        return nil
    }

    let configuration = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
        let delete = UIAction(title: "Delete", image: UIImage(systemName: "trash.fill"), attributes: .destructive) { _ in
            self.deleteItem(item)
        }

        return UIMenu(title: "", image: nil, identifier: nil, children: [delete])
    }
    return configuration
}

Если я удалю элемент вне контекстного меню, анимация будет работать отлично. Если я удаляю из контекстного меню, одна ячейка исчезает, а затем мигает следующая. Я подозреваю, что существует какой-то конфликт между закрытием контекстного меню и запуском анимации удаления. Я ищу способ обойти это.

1 ответ

edit: Это было очень стабильно, что приводило к зависанию пользовательского интерфейса и другим странным сбоям, когда он иногда не реагировал на долгое нажатие, не используйте это. Хотелось бы, чтобы в этом API не было такого сбоя, это очень раздражает.

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

Сначала добавьте взаимодействие к своим ячейкам contentView

let interaction = UIContextMenuInteraction(delegate: self)
cell.contentView.addInteraction(interaction)

Затем реализуйте делегат, предположительно там, где вы представляете ячейку, в моем случае в viewController

extension ViewController : UIContextMenuInteractionDelegate {
    func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {

        // loop through all visible cells to find which one we interacted with
        guard let cell = collectionView.visibleCells.first(where: { $0.contentView == interaction.view }) else {
            return nil
        }

        // convert it to an indexPath
        guard let indexPath = collectionView.indexPath(for: cell) else {
            return nil
        }

        // continue with your magic!
    }
}

И вуаля, вот и все, больше никакой глючной анимации. Я не знаю, есть ли какие-нибудь крайние случаи, когда будет выбрана неправильная ячейка или другие странные вещи, но, похоже, это работает нормально.