KDDragAndDropCollectionViews 1.5.2

KDDragAndDropCollectionViews 1.5.2

维护者:Michael Michailidis.



  • 作者:
  • Michael Michailidis

拖放CollectionView

为 Swift 4.0 编写,实现跨多个 UICollectionView 的拖放数据。

Drag and Drop Illustration

在 Appetize.io 上试一试:Appetize.io!

Language Licence CocoaPods Awesome

要求

  • iOS 8.0+
  • XCode 9.0+
  • Swift 4.0+

安装

Cocoa Pods

pod 'KDDragAndDropCollectionViews', '~> 1.5.2'

手动安装

Classes/ 目录中的文件添加到项目中。

快速指南

将UICollectionView设置为

XCode Interface Builder Screen

然后设置一个类作为dataSource并实现协议。

class ViewController: UIViewController, KDDragAndDropCollectionViewDataSource {

    @IBOutlet weak var firstCollectionView: KDDragAndDropCollectionView!
    @IBOutlet weak var secondCollectionView: KDDragAndDropCollectionView!
    @IBOutlet weak var thirdCollectionView: KDDragAndDropCollectionView!
    
    var data : [[DataItem]] = [[DataItem]]() // just for this example
    
    var dragAndDropManager : KDDragAndDropManager?
    
    override func viewDidLoad() {
        let all = [firstCollectionView, secondCollectionView, thirdCollectionView]
        self.dragAndDropManager = KDDragAndDropManager(canvas: self.view, collectionViews: all)
    }
}

用户代码的唯一责任是管理代表收集视图单元格的数据。收集视图的数据源必须实现协议。

在示例中,我们使用了3个具有各自标签的UICollectionView(我知道这是不好的实践,但只是示例...),以及包含3个数组的数组数据。在这种情况下,上述实现的示例可能是

func collectionView(collectionView: UICollectionView, dataItemForIndexPath indexPath: NSIndexPath) -> AnyObject {
    return data[collectionView.tag][indexPath.item]
}

func collectionView(collectionView: UICollectionView, insertDataItem dataItem : AnyObject, atIndexPath indexPath: NSIndexPath) -> Void {
    if let di = dataItem as? DataItem {
        data[collectionView.tag].insert(di, atIndex: indexPath.item)
    }
}

func collectionView(collectionView: UICollectionView, deleteDataItemAtIndexPath indexPath : NSIndexPath) -> Void {
    data[collectionView.tag].removeAtIndex(indexPath.item)
}

func collectionView(collectionView: UICollectionView, moveDataItemFromIndexPath from: NSIndexPath, toIndexPath to : NSIndexPath) -> Void {
    let fromDataItem: DataItem = data[collectionView.tag][from.item]
    data[collectionView.tag].removeAtIndex(from.item)
    data[collectionView.tag].insert(fromDataItem, atIndex: to.item)    
}

func collectionView(_ collectionView: UICollectionView, indexPathForDataItem dataItem: AnyObject) -> IndexPath? {

    guard let candidate = dataItem as? DataItem else { return nil }
    
    for (i,item) in data[collectionView.tag].enumerated() {
        if candidate != item { continue }
        return IndexPath(item: i, section: 0)
    }
    return nil
}

高级使用

防止特定项目被拖动和/或丢弃

对于更精细地调整哪些项目可以拖动以及哪些不能拖动,我们可以实现来自协议的以下功能

func collectionView(_ collectionView: UICollectionView, cellIsDraggableAtIndexPath indexPath: IndexPath) -> Bool {
    return indexPath.row % 2 == 0
}

数据项和Equatable

在项目中包含的示例代码中,我创建了一个类来表示收集视图显示的数据。

class DataItem : Equatable {
    var indexes: String
    var colour: UIColor
    init(indexes: String, colour: UIColor = UIColor.clear) {
        self.indexes    = indexes
        self.colour     = colour
    }
    static func ==(lhs: DataItem, rhs: DataItem) -> Bool {
        return lhs.indexes == rhs.indexes && lhs.colour == rhs.colour
    }
}

在开发过程中,您将创建自己的类型,这些类型必须遵守上述协议。每个数据项都必须是唯一标识的,所以在创建单元格时要小心,因为样本显示值可能会有重复,例如在"Scrabble"类型游戏中,相同的字母出现多次。在这种情况下,一个简单的标识符就足以实现等价。