4

我采用了新的 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
}

如果我从上下文菜单之外删除该项目,则动画效果很好。如果我从上下文菜单中删除,则一个单元格消失,然后导致下一个单元格闪烁。我怀疑关闭上下文菜单和运行删除动画之间存在某种冲突。我正在寻找解决此问题的方法。

4

1 回答 1

-1

edit: This was very stable resulting in freezing of the UI and other weird glitches where it sometimes didn't respond to long-press, do not use this. I wish this API didn't have that glitch, it's very annoying.

I found this ugly glitch too and was very close on giving up until I thought I'd give it a shot implementing the other interaction API instead of the built-in on UICollectionView, weirdly enough the animation went away.

First add the interaction to your cells contentView

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

Then implement the delegate, presumably where you present the cell, in my case in the 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!
    }
}

And voila, that's it, no more glitchy animation. I don't know if there's some edge cases where wrong cell will be selected or other weird stuff, but this seems to work just fine.

于 2020-06-14T22:37:41.893 回答