简体   繁体   中英

Reorder items in NSCollectionView with drag and drop, swift 3+

I have spent days trying so many different things to make this work, but am consistently failing. This is starting to become depressing and I would really like an idea from someone who knows how to make user drag and drop work to reorder the items within an NSCollectionView. This is my latest attempt, which does absolutely nothing at all:

let MyItemType = "myItemType"
class CollectionViewController: NSViewController {
@IBOutlet weak var collectionView: NSCollectionView!
let MyItemType = "myItemType"
override func viewDidLoad() {
    super.viewDidLoad()
    configureCollectionView()
    loadDevices()
    getstate()
    // try to register drag and drop (all attempts fail)
    //collectionView.register(forDraggedTypes: [MyItemType, NSFilenamesPboardType]
}
// more functions here were omitted...
}

extension CollectionViewController : NSCollectionViewDataSource {

func numberOfSections(in collectionView: NSCollectionView) -> Int {
    return 1
}

func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
    return groupbuttons.count
}

func collectionView(_ itemForRepresentedObjectAtcollectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {

    let item = collectionView.makeItem(withIdentifier: "CollectionViewItem", for: indexPath)
    guard let collectionViewItem = item as? CollectionViewItem else {return item}

    let button = groupbuttons[indexPath.item]
    collectionViewItem.button = button
    return item
}
/* try to implement drag and drop reordering (all attempts fail)
func collectionView(collectionView: NSCollectionView, canDragItemsAtIndexes indexes: NSIndexSet, withEvent event: NSEvent) -> Bool {
    return true
}
func collectionView(_ collectionView: NSCollectionView, writeItemsAtIndexes indexes: NSIndexSet, to toPasteboard: NSPasteboard) -> Bool {
    let data = NSKeyedArchiver.archivedData(withRootObject: [indexes])
    toPasteboard.declareTypes([MyItemType], owner:self)
    toPasteboard.setData(data, forType:MyItemType)
    return true
}

func collectionView(_ collectionView: NSCollectionView, validateDrop info: NSDraggingInfo, proposedIndex index: Int, proposedDropOperation dropOperation: NSCollectionViewDropOperation) -> NSDragOperation {

    //collectionView.setDropIndex(index, dropOperation: NSCollectionViewDropOperation.above)
    return NSDragOperation.move
}
func collectionView(_ collectionView: NSCollectionView, acceptDrop info: NSDraggingInfo, index: Int, dropOperation: NSTableViewDropOperation) -> Bool {
    let pasteboard = info.draggingPasteboard()
    let itemData = pasteboard.data(forType: MyItemType)

    if(itemData != nil) {
        var dataArray = NSKeyedUnarchiver.unarchiveObject(with: itemData!) as! Array<IndexSet>,
        indexSet = dataArray[0]

        let movingFromIndex = indexSet.first
        let item = groupbuttons[movingFromIndex!]

        _moveItem(item, from: movingFromIndex!, to: index)

        return true
    }
    else {
        return false
    }
}
func _moveItem(_ item: GroupButton, from: Int, to: Int) {
    groupbuttons.remove(at: from)

    if(to > groupbuttons.endIndex) {
        groupbuttons.append(item)
    }
    else {
        groupbuttons.insert(item, at: to)
    }
    collectionView.reloadData()
}
*/


}

If anyone has been able to get drag and drop reordering to work with NSCollectionView, I would appreciate any help. Or maybe it is not possible in this circumstance? I am not sure why drag and drop item reordering is so complicated.

I have passed by the same situation and I finally figured out how to do it. Here is my code using Swift 4:

ViewDidLoad

var indiceItensMovidosDrag: Set<IndexPath> = []

override func viewDidLoad() {
        super.viewDidLoad()

        fotosProdutoLojaCollectionView.delegate = self
        fotosProdutoLojaCollectionView.dataSource = self
        fotosProdutoLojaCollectionView.registerForDraggedTypes([NSPasteboard.PasteboardType(kUTTypeItem as String)])

        fotosProdutoLojaCollectionView.setDraggingSourceOperationMask(.move, forLocal: true)

        if produtoLoja == nil {
            produtoLoja = ProdutoLoja()
        }
}

Now the delegate and data source methods methods

    func numberOfSections(in collectionView: NSCollectionView) -> Int {

        return 1
    }

    func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {

        return produtoLoja!.fotos.count
    }

    func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {

        var item = NSCollectionViewItem()

        item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "FotoProdutoLojaCollectionViewItem"), for: indexPath)

        let fotosProdutoLojaCollectionViewItem = item as! FotoProdutoLojaCollectionViewItem

        produtoLoja?.fotos[indexPath.item].foto?.getDataInBackground(block: {
            (data: Data?, error: Error?) -> Void in

            if error == nil {
                fotosProdutoLojaCollectionViewItem.fotoProdutoLojaImageView.image = NSImage(data: data!)
            }
        })

        if produtoLoja!.fotos[indexPath.item].imagemCapa {
            fotosProdutoLojaCollectionViewItem.fotoCapaImageView.isHidden = false
        }else {
            fotosProdutoLojaCollectionViewItem.fotoCapaImageView.isHidden = true
        }

        return item
    }

func collectionView(_ collectionView: NSCollectionView, canDragItemsAt indexPaths: Set<IndexPath>, with event: NSEvent) -> Bool {

        return true
    }

    func collectionView(_ collectionView: NSCollectionView, pasteboardWriterForItemAt indexPath: IndexPath) -> NSPasteboardWriting? {

        let retorno = NSPasteboardItem()

        var data: Data?
        do {
            try data = produtoLoja?.fotos[indexPath.item].foto?.getData()
        } catch {

        }

        retorno.setData(data!, forType: NSPasteboard.PasteboardType(kUTTypeItem as String))

        return retorno
    }

    func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, willBeginAt screenPoint: NSPoint, forItemsAt indexPaths: Set<IndexPath>) {

        indiceItensMovidosDrag = indexPaths
    }

    func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, endedAt screenPoint: NSPoint, dragOperation operation: NSDragOperation) {

        indiceItensMovidosDrag = []
    }

    func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer<NSIndexPath>, dropOperation proposedDropOperation: UnsafeMutablePointer<NSCollectionView.DropOperation>) -> NSDragOperation {

        if proposedDropOperation.pointee == NSCollectionView.DropOperation.on {
            proposedDropOperation.pointee = NSCollectionView.DropOperation.before
        }

        return NSDragOperation.move
    }

    func collectionView(_ collectionView: NSCollectionView, acceptDrop draggingInfo: NSDraggingInfo, indexPath: IndexPath, dropOperation: NSCollectionView.DropOperation) -> Bool {

        var retorno = true

        if indiceItensMovidosDrag.count == 1 {
            for indice in indiceItensMovidosDrag {
                collectionView.animator().moveItem(at: indice, to: (indexPath.item <= indice.item) ? indexPath : (IndexPath(item: indexPath.item - 1, section: 0)))

            }
        } else {
            mostrarErro(mensagem: "Erro", informativo: "Só é possível mover uma imagem por vez")
            retorno = false
        }

        //fotosProdutoLojaCollectionView.reloadData()

        return retorno
    }

Hope it helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM