UICollectionView拖拽重排时如何检测cell视觉位置切换的时机?
检测UICollectionView拖拽重排时cell视觉交换时机的实现方案
有两种常用的实现方式,优先推荐第一种系统原生回调方案,准确性更高:
方案1:使用UICollectionViewDelegate原生回调
系统在拖拽过程中,每次判定需要触发cell位置交换时,都会调用collectionView(_:targetIndexPathForMoveFromItemAt:toProposedIndexPath:)代理方法,你可以直接在该方法中捕获交换时机:
- 首先让你的控制器遵守
UICollectionViewDelegate协议,确保collectionView的delegate属性设置为self - 实现代理方法:
extension DashboardViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath { // 此处即为视觉位置发生交换的触发点 print("Cell 从位置\(originalIndexPath.item)交换到位置\(proposedIndexPath.item)") // 若不需要修改交换目标位置,直接返回系统提议的indexPath即可 return proposedIndexPath } }
注意:使用UICollectionView交互移动功能,必须同时实现
UICollectionViewDataSource的collectionView(_:moveItemAt:to:)方法更新你的数据源,避免出现数据和UI不一致的崩溃问题。
方案2:手动在手势回调中检测
如果你需要自定义判断逻辑,也可以在长按手势的changed状态中手动比对indexPath变化:
- 新增两个状态属性:
class DashboardViewController { // 记录当前拖拽的起始IndexPath private var draggingIndexPath: IndexPath? // 记录上一次触发交换的目标IndexPath private var lastMovedIndexPath: IndexPath? // 原有代码保持不变... }
- 修改手势对应的状态处理方法:
func began(_ gesture: UILongPressGestureRecognizer) { let location = gesture.location(in: self.collectionView) guard let indexPath = self.collectionView.indexPathForItem(at: location) else { return } // 初始化拖拽状态 draggingIndexPath = indexPath lastMovedIndexPath = indexPath collectionView.beginInteractiveMovementForItem(at: indexPath) } func changed(_ gesture: UILongPressGestureRecognizer) { let location = gesture.location(in: collectionView) collectionView.updateInteractiveMovementTargetPosition(location) // 检测位置变化 guard let currentTargetIndexPath = collectionView.indexPathForItem(at: location), let last = lastMovedIndexPath, currentTargetIndexPath != last else { return } // 触发位置交换逻辑 print("Cell 从位置\(last.item)交换到位置\(currentTargetIndexPath.item)") lastMovedIndexPath = currentTargetIndexPath } func ended(_ gesture: UILongPressGestureRecognizer) { collectionView.endInteractiveMovement() // 清空状态 draggingIndexPath = nil lastMovedIndexPath = nil } func cancel(_ gesture: UILongPressGestureRecognizer) { collectionView.endInteractiveMovement() // 清空状态 draggingIndexPath = nil lastMovedIndexPath = nil }
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng
相关产品推荐
相关产品推荐

