如何在NSCollectionView

时间:2017-02-18 12:44:18

标签: swift drag-and-drop nscollectionview nspasteboard

我有一个部分的集合视图,并希望实现拖放以允许重新排序项目。 CollectionViewItem有几个文本视图,显示我的Parameter对象的属性。阅读我需要实施NSCollectionView delegate

的文档
func collectionView(_ collectionView: NSCollectionView, pasteboardWriterForItemAt indexPath: IndexPath) -> NSPasteboardWriting? {
    let parameter = parameterForIndexPath(indexPath: indexPath)
    return parameter // throws an error "Cannot convert return expression of type 'Parameter' to return type 'NSPasteboardWriting?'"
}

我没有找到任何可以理解NSPasteboardWriting对象性质的信息。所以,我不知道如何继续...... 什么是NSPasteboardWriting对象以及我需要在粘贴板中写什么?

谢谢!

2 个答案:

答案 0 :(得分:6)

免责声明:我一直在努力寻找能够以对我有意义的方式解释这一点,特别是对于Swift,并且不得不将以下内容拼凑在一起并遇到很多困难。如果你知道的更好,请告诉我,我会纠正它!

“pasteboardwriter”方法(例如您的问题中的方法)必须返回可以拖动的项目可识别的内容,可以将其写入粘贴板。然后拖放方法绕过此粘贴板项目。

我见过的大多数例子只是使用对象的字符串表示。您需要这样,以便在acceptDrop方法中,您可以将手放回原始对象(被拖动的项目)。然后,您可以重新订购该项目的位置,或者您需要采取的任何行动。

拖放涉及四个主要步骤。我目前正在使用源列表视图执行此操作,因此我将使用该示例而不是您的集合视图。

  1. viewDidLoad() 注册源列表视图以接受已删除的对象。通过告诉它应该接受哪种粘贴板类型来做到这一点。

    // Register for the dropped object types we can accept. sourceList.register(forDraggedTypes: [REORDER_SOURCELIST_PASTEBOARD_TYPE])

    我在这里使用自定义类型REORDER_SOURCELIST_PASTEBOARD_TYPE,我将其定义为常量,如下所示:

       `let REORDER_SOURCELIST_PASTEBOARD_TYPE = "com.yourdomain.sourcelist.item"`
    

    ...其中值是您的应用所特有的内容,即yourdomain应更改为您应用的特定内容,例如com.myapp.sourcelist.item

    我在任何类之外定义它(因此可以从几个类访问它),如下所示:

       import Cocoa
    
       let REORDER_SOURCELIST_PASTEBOARD_TYPE = "com.yourdomain.sourcelist.item"`
    
       class Something {
          // ...etc...
    
  2. 实施视图的pasteboardWriterForItem方法。根据您使用的视图(即源列表,集合视图或其他),这会略有不同。对于源列表,它看起来像这样:

      // Return a pasteboard writer if this outlineview's item should be able to 
      // drag-and-drop.
      func outlineView(_ outlineView: NSOutlineView, pasteboardWriterForItem item: Any) -> NSPasteboardWriting? {
        let pbItem = NSPasteboardItem()
    
        // See if the item is of the draggable kind. If so, set the pasteboard item.
        if let draggableThing = ((item as? NSTreeNode)?.representedObject) as? DraggableThing {
              pbItem.setString(draggableThing.uuid, forType: REORDER_SOURCELIST_PASTEBOARD_TYPE)
              return pbItem;
        }
    
        return nil
      }
    

    最引人注目的部分是draggableThing.uuid,它只是一个字符串,可以通过其粘贴板唯一地标识拖动的对象。

  3. 弄清楚您所拖动的项目是否可以在给定索引的建议项目上删除,如果是,则返回应该是的丢弃类型。

    func outlineView(_ outlineView: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
        // Get the pasteboard types that this dragging item can offer. If none
        // then bail out.
        guard let draggingTypes = info.draggingPasteboard().types else {
            return []
        }
    
        if draggingTypes.contains(REORDER_SOURCELIST_PASTEBOARD_TYPE) {
            if index >= 0 && item != nil {
                return .move
            }
          }
    
          return []
        }
    
  4. 处理放置事件。执行诸如将拖动的项目移动到数据模型中的新位置并重新加载视图或移动视图中的行等操作。

    func outlineView(_ outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
      let pasteboard = info.draggingPasteboard()
    
      let uuid = pasteboard.string(forType: REORDER_SOURCELIST_PASTEBOARD_TYPE)
    
      // Go through each of the tree nodes, to see if this uuid is one of them.
      var sourceNode: NSTreeNode?
      if let item = item as? NSTreeNode, item.children != nil {
        for node in item.children! {
            if let collection = node.representedObject as? Collection {
                if collection.uuid == uuid {
                    sourceNode = node
                }
            }
        }
      }
    
      if sourceNode == nil {
        return false
      }
    
      // Reorder the items.
      let indexArr: [Int] = [1, index]
      let toIndexPath = NSIndexPath(indexes: indexArr, length: 2)
      treeController.move(sourceNode!, to: toIndexPath as IndexPath)
    
      return true
    }
    
  5. 旁白:我们使用粘贴板项目进行拖放的Cocoa命令对我来说似乎是非常不必要的 - 为什么它不能简单地传递我不知道的原始(即拖动)对象!显然有些drags来自应用程序之外,但是对于那些源自它的人来说,确定传递对象会保留所有与粘贴板一起跳跃的跳跃。

答案 1 :(得分:0)

NSPasteboardWriting 协议提供了 NSPasteboard(好吧,我猜是技术上的任何人)可以用来生成对象的不同表示的方法,用于在粘贴板周围传输,这是一个较旧的 Apple 概念,用于复制/粘贴(因此粘贴板),并且显然在某些情况下用于拖放。

看来,基本上,协议的自定义实现需要实现以下方法:

另一个答案提供了该协议的直接实现,可在单个应用中使用。


但实际上?

<块引用>

Cocoa 框架类 NSString、NSAttributedString、NSURL、NSColor、NSSound、NSImage 和 NSPasteboardItem 实现了这个协议。

因此,如果您有一个可以完全表示为 URL(或字符串、颜色、声音或图像等)的可拖动项目,只需将您拥有的 URL 转换为 {{1} }:

NSPasteboardWriting?

如果您有一个复杂的类型,这没有帮助,但如果您有图像的集合视图或其他一些基本项目,我希望它会有所帮助。