如何在自定义组合布局下使用UICollectionViewDiffableDataSource的reorderHandlers实现重排
不依赖列表单元格/重排附件启用UICollectionViewDiffableDataSource重排的方案
reorderingHandlers本质是对UICollectionView原生重排交互能力的封装,本身不绑定列表布局、列表单元格或者重排附件,按以下步骤配置即可正常使用:
- 给UICollectionView添加长按手势识别器
列表单元格的重排附件自带了触发重排的手势逻辑,自定义场景下需要自行添加交互触发入口:
let longPressGR = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:))) collectionView.addGestureRecognizer(longPressGR)
- 实现手势处理方法,调用系统重排交互接口
在手势状态变化时调用UICollectionView对应的交互方法,系统会自动触发reorderingHandlers的相关闭包:
@objc private func handleLongPress(_ gesture: UILongPressGestureRecognizer) { let touchLocation = gesture.location(in: collectionView) switch gesture.state { case .began: guard let targetIndexPath = collectionView.indexPathForItem(at: touchLocation) else { return } collectionView.beginInteractiveMovementForItem(at: targetIndexPath) case .changed: collectionView.updateInteractiveMovementTargetPosition(touchLocation) case .ended: collectionView.endInteractiveMovement() default: collectionView.cancelInteractiveMovement() } }
- 正常配置
reorderingHandlers的两个闭包
不需要做任何列表相关的适配,直接按官方文档实现两个闭包即可:
// 配置允许重排的item规则 dataSource.reorderingHandlers.canReorderItem = { item in return true // 可根据业务需求返回对应item是否支持重排 } // 处理重排完成后的逻辑 dataSource.reorderingHandlers.didReorder = { [weak self] transaction in guard let self = self else { return } // 从transaction中获取重排后的顺序,更新本地数据源 let updatedItems = transaction.difference.inferringMoves().reduce(into: self.originItems) { items, change in switch change { case .remove(let offset, _, let moveTo): if let move = moveTo { items.remove(at: offset) items.insert(change.element, at: move.offset) } default: break } } self.originItems = updatedItems }
额外注意事项
- 组合布局的网格配置原生支持重排,不需要额外修改布局逻辑;如果是完全自定义的UICollectionViewLayout,需要实现重排时的位置计算相关方法
- 不需要继承
UICollectionViewListCell,普通自定义UICollectionViewCell完全适配该方案
内容的提问来源于stack exchange,提问作者Tom Hamming
相关产品推荐
相关产品推荐

