能否在UICollectionViewDropProposal中同时设置两种插入意图以实现iOS提醒功能?
关于UICollectionView拖拽同时支持两种插入意图的实现方案
首先明确:你无法直接返回同时包含.insertAtDestinationIndexPath和.insertIntoDestinationIndexPath的UICollectionViewDropProposal,因为UICollectionViewDropIntent是单一枚举类型,每个DropProposal只能设置一个意图值。
iOS提醒事项的拖拽效果,本质是根据拖拽时的位置动态切换这两种插入意图,核心实现思路如下:
- 当拖拽项目悬停在单元格的外部间隙时,返回
.insertAtDestinationIndexPath,实现插入到目标单元格的上方或下方 - 当拖拽项目悬停在单元格的内部特定区域时,返回
.insertIntoDestinationIndexPath,实现将项目插入到该单元格对应的分组/列表中
具体实现步骤
- 在
dropSessionDidUpdate方法中,先校验destinationIndexPath的有效性 - 通过
collectionView.indexPathForItem(at: session.location(in: collectionView))获取当前悬停的单元格索引路径 - 根据拖拽位置与单元格的相对位置(比如判断触摸点是否落在单元格内部的指定区域),动态选择插入意图:
- 若需插入到分组内,创建
UICollectionViewDropProposal(operation: .copy/.move, intent: .insertIntoDestinationIndexPath) - 若需插入到单元格之间,创建
UICollectionViewDropProposal(operation: .copy/.move, intent: .insertAtDestinationIndexPath)
- 若需插入到分组内,创建
示例代码片段
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal { guard let destinationIndexPath = destinationIndexPath else { return UICollectionViewDropProposal(operation: .cancel) } let location = session.location(in: collectionView) if let hoveredIndexPath = collectionView.indexPathForItem(at: location) { guard let cell = collectionView.cellForItem(at: hoveredIndexPath) else { return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) } let cellFrame = collectionView.convert(cell.frame, to: collectionView) // 示例逻辑:触摸点落在单元格上半部分时触发插入到分组内,下半部分插入到单元格之间 let isInsideCell = location.y > cellFrame.minY && location.y < cellFrame.maxY let shouldInsertInto = isInsideCell && (location.y - cellFrame.minY) < cellFrame.height * 0.5 if shouldInsertInto { return UICollectionViewDropProposal(operation: .move, intent: .insertIntoDestinationIndexPath) } else { return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) } } return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) }
补充说明
还需要配合实现collectionView(_:performDropWith:)方法,根据当前的意图处理对应插入逻辑:
- 当意图为
.insertIntoDestinationIndexPath时,将拖拽数据添加到目标分组的数据源中 - 当意图为
.insertAtDestinationIndexPath时,将拖拽数据插入到目标索引路径的位置
内容的提问来源于stack exchange,提问作者Nikodem
相关产品推荐
相关产品推荐

