之前大概写了一次collectionView中实现拖拽效果的基本使用跳转查看,在查资料的时候看到有人做了个类似商品选择的交互挺有意思,经原作者同意改写了一版,转载于此。交互效果如下
拖拽效果实现
两个collectionView的布局和两个cell的自定义就不赘述了,具体可参考下方的项目链接。这个demo里实现了从food的collectionView上拖拽,并且拖拽到user的collectionView上,dragDelegate
给到food的collectionView并实现对应的代理方法
这里可以注意下,正常来说拖拽某个cell,会拖拽cell整体,交互上想要实现只拖拽cell中的某个元素(这里是只拖拽food的image),需要实现dragPreviewParametersForItemAt
,自己绘制出要Preview的rect即可
func collectionView(_ collectionView: UICollectionView, dragPreviewParametersForItemAt indexPath: IndexPath) -> UIDragPreviewParameters? {
if collectionView == foodCollectionView {
let previewParameters = UIDragPreviewParameters()
previewParameters.visiblePath = UIBezierPath(roundedRect: CGRect(x: 20, y: 12, width: 60, height: 60), cornerRadius: 18)
return previewParameters
}
return nil
}
我这里设置UIBezierPath的CGRect的值,是完全用FoodCell里food的imageView的布局信息
拖拽到目标collectionView
food图片拖拽后到指定的user collectionView上,并实现目标user的cell重绘。首先要把dropDelegate
给到user的collectionView,实现基本的performDropWith
方法,该方法主要控制对destinationIndexPath的操作,确定destinationIndexPath就确定了最终要拖拽到的indexPath
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: any UICollectionViewDropCoordinator) {
var destinationIndexPath: IndexPath
if let indexPath = coordinator.destinationIndexPath {
destinationIndexPath = indexPath
} else {
let row = collectionView.numberOfItems(inSection: 0)
destinationIndexPath = IndexPath(item: row - 1, section: 0)
}
if collectionView == userCollectionView {
if coordinator.proposal.operation == .copy {
copyItems(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
}
}
}
copyItems是自己定义的逻辑处理方法,通过传递UICollectionViewDropCoordinator
类型的coordinator参数,可以拿到拖拽的food信息。通过destinationIndexPath
可以拿到具体要更新哪个user的信息,完成collectionView的重绘
private func copyItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) {
collectionView.performBatchUpdates {
for (_, item) in coordinator.items.enumerated() {
if collectionView === userCollectionView {
let productPrice = item.dragItem.localObject as? String
if let price = productPrice, let intPrice = Int(price) {
users[destinationIndexPath.item].amount += intPrice
users[destinationIndexPath.item].items += 1
UIView.performWithoutAnimation {
collectionView.reloadSections(IndexSet(integer: 0))
}
}
}
}
}
}