collectionView的Drag和Drop交互

48 阅读2分钟

之前大概写了一次collectionView中实现拖拽效果的基本使用跳转查看,在查资料的时候看到有人做了个类似商品选择的交互挺有意思,经原作者同意改写了一版,转载于此。交互效果如下

udom6-5brhc.gif

拖拽效果实现

两个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))
                    }
                }
            }
        }
    }
}

项目链接