Как перетащить элементы из NSCollectionView

Я пытаюсь реализовать перетаскивание элементов из NSCollectionView (не просто перетаскивая объекты на него).

В моем примере кода я регистрирую CollectionView от перетаскивания:

collectionView.registerForDraggedTypes([.URL])
collectionView.setDraggingSourceOperationMask(.every, forLocal: false)
collectionView.setDraggingSourceOperationMask(.every, forLocal: true)

Затем я реализовал эти методы из протокола NSCollectionViewDelegate:

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

func collectionView(_ collectionView: NSCollectionView, pasteboardWriterForItemAt indexPath: IndexPath) -> NSPasteboardWriting? {    
    return URL(fileURLWithPath: #file) as NSPasteboardWriting
}

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

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

Но ни один из них никогда не называется! Почему бы и нет?

Если я добавлю эти два метода:

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

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

Затем я могу успешно перенести файлы с рабочего стола в представление коллекции, но все равно не наоборот.

В чем дело?

С уважением, В.

1 ответ

Точно так же и здесь.

Это похоже на ошибку (Xcode 9.4.1, Swit 4.1.2).

Так же, как вы упомянули, validateDrop а также acceptDrop позвонить в моем приложении.
Но (например), endedAt не:

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

Единственный обходной путь, который я мог найти (для вышеупомянутого endedAt делегат) должен был подкласс NSCollectionView (который я звоню ImageCollectionView в приведенном ниже примере) и реализовать свой собственный delegate/protocol:

import Cocoa

protocol ImageCollectionViewDelegate {
    func didExitDragging()
}

class ImageCollectionView: NSCollectionView {
    var imageCollectionViewDelegate: ImageCollectionViewDelegate?
}

extension ImageCollectionView {
    override func draggingExited(_ sender: NSDraggingInfo?) {
        super.draggingExited(sender)
        imageCollectionViewDelegate?.didExitDragging()
    }
}

(Я должен был назвать это imageCollectionViewDelegate не противоречить уже существующим delegate имущество.)

Затем в моем контроллере (который я называю ImageCollectionViewController):

@IBOutlet internal weak var imageCollectionView: ImageCollectionView! {
    didSet {
        imageCollectionView.imageCollectionViewDelegate = self
    }
}

extension ImageCollectionViewController: ImageCollectionViewDelegate {
    func didExitDragging() {
        highlightDestination(false)
    }
}

Это позволяет мне делать вещи при перетаскивании за пределы коллекции.
В этом очень простом случае просто включите / выключите выделение целевого вида:

подсветка

В идеале весь этот дополнительный код не был бы необходим.

Я также ищу правильный способ справиться с этим.

Другие вопросы по тегам