首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用UICollectionViewDiffableDataSource和NSFetchedResultsController重排细胞

用UICollectionViewDiffableDataSource和NSFetchedResultsController重排细胞
EN

Stack Overflow用户
提问于 2019-09-20 13:25:19
回答 2查看 1.2K关注 0票数 9

我使用一个UICollectionViewDiffableDataSource和一个NSFetchedResultsControllerNSFetchedResultsController中填充我的UICollectionView

为了增加重新排序单元的能力,我添加了一个UILongPressGestureRecognizer和子类UICollectionViewDiffableDataSource,以便使用它的canMoveItemAt:moveItemAt:方法。

当重新排序单元格时,会发生以下情况:

  1. 调用moveItemAt:,我更新对象位置属性并保存MOC。
  2. 调用controllerDidChangeContent: of NSFetchedResultsControllerDelegate,我从当前的fetchedObjects创建一个新的快照并应用它。

当我应用dataSource?.apply(snapshot, animatingDifferences: true)时,单元格会立即切换回位置。如果我设置了animatingDifferences: false,它就能工作,但是所有的单元格都可以明显地重新加载。

这里有什么最佳实践吗?如何在UICollectionViewDiffableDataSourceNSFetchedResultsController上实现单元格重新排序?

以下是我提到的方法:

代码语言:javascript
复制
// ViewController 
func createSnapshot(animated: Bool = true) {
    var snapshot = NSDiffableDataSourceSnapshot<Int, Favorite>()
    snapshot.appendSections([0])
    snapshot.appendItems(provider.fetchedResultsController.fetchedObjects ?? [])
    dataSource?.apply(snapshot, animatingDifferences: animated)
}

// NSFetchedResultsControllerDelegate
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    createSnapshot(animated: false)
}

// Subclassed UICollectionViewDiffableDataSource
override func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    provider.moveFavorite(from: sourceIndexPath.row, to: destinationIndexPath.row)
}

// Actual cell moving in a provider class
public func moveFavorite(from source: Int, to destination: Int) {
    guard let favorites = fetchedResultsController.fetchedObjects else { return }
    if source < destination {
        let partialObjects = favorites.filter({ $0.position <= destination && $0.position >= source })

        for object in partialObjects {
            object.position -= 1
        }

        let movedFavorite = partialObjects.first
        movedFavorite?.position = Int64(destination)
    }
    else {
        let partialObjects = favorites.filter({ $0.position >= destination && $0.position <= source })

        for object in partialObjects {
            object.position += 1
        }

        let movedFavorite = partialObjects.last
        movedFavorite?.position = Int64(destination)
    }
    do {
        try coreDataHandler.mainContext.save()
    } catch let error as NSError {
        print(error.localizedDescription)
    }
}
EN

回答 2

Stack Overflow用户

发布于 2020-03-22 17:27:05

相同问题的解决方案是对UICollectionViewDiffableDataSource进行子类化,并在子类中实现canMoveItemAt方法以回答true。如果longPressAction的.ended案例做了三件事,动画对我来说似乎很好:

  1. 更新模型
  2. 呼叫dateSource.collectionView(..moveItemAt:..)
  3. 运行您的dataSource.apply

用于拖动行为的其他常用方法也必须实现,看起来就像您所做的那样。其他方法-这些方法在UICollectionView的“交互式重新排序”一节中有很好的文档。https://developer.apple.com/documentation/uikit/uicollectionview

代码语言:javascript
复制
class PGLDiffableDataSource: UICollectionViewDiffableDataSource<Int, Int> {
    override func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
        return true
    }

}
票数 1
EN

Stack Overflow用户

发布于 2020-12-19 05:03:23

不需要子类。从iOS 14.0开始,UICollectionViewDiffableDataSource支持您可以实现的重新排序处理程序

代码语言:javascript
复制
let data_source = UICollectionViewDiffableDataSource<MySection, MyModelObject>( collectionView: collection_view, cellProvider:
{
    [weak self] (collection_view, index_path, video) -> UICollectionViewCell? in
        
    let cell = collection_view.dequeueReusableCell( withReuseIdentifier: "cell", for: index_path ) as! MyCollectionViewCell

    if let self = self
    {
        //setModel() is my own method to update the view in MyCollectionViewCell
        cell.setModel( self.my_model_objects[index_path.item] )
    }

    return cell
})

// Allow every item to be reordered as long as there's 2 or more
diffable_data_source.reorderingHandlers.canReorderItem = 
{ 
    item in 
    my_model_objects.count >= 2 return true 
}

//Update your model objects before the reorder occurs. 
//You can also use didReorder, but it might be useful to have your
//model objects in the correct order before dequeueReusableCell() is 
//called so you can update the cell's view with the correct model object.
diffable_data_source.reorderingHandlers.willReorder = 
{ 
    [weak self] transaction in
    
    guard let self = self else { return }
    
    self.my_model_objects = transaction.finalSnapshot.itemIdentifiers
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58029290

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档