如何利用NSOutlineView的pasteboardWriterForItem:实现多条目写入?
解决NSOutlineView多条目拖放的标准实现
1. 定义自定义粘贴板类型与数据模型
首先定义唯一的粘贴板类型标识,再让你的数据模型类遵循NSPasteboardWriting和NSPasteboardReading协议,实现序列化/反序列化逻辑:
private let OutlineItemPasteboardType = NSPasteboard.PasteboardType("com.yourcompany.outlineitem") class OutlineItem: NSObject, NSPasteboardWriting, NSPasteboardReading { var title: String var children: [OutlineItem] = [] init(title: String) { self.title = title super.init() } // MARK: NSPasteboardWriting func writableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] { return [OutlineItemPasteboardType] } func pasteboardPropertyList(forType type: NSPasteboard.PasteboardType) -> Any? { guard type == OutlineItemPasteboardType else { return nil } // 序列化数据,复杂结构可改用JSON/PropertyList return ["title": title] } // MARK: NSPasteboardReading static func readableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] { return [OutlineItemPasteboardType] } static func readingOptions(forType type: NSPasteboard.PasteboardType, pasteboard: NSPasteboard) -> NSPasteboard.ReadingOptions { return .asPropertyList } required init?(pasteboardPropertyList propertyList: Any, ofType type: NSPasteboard.PasteboardType) { guard type == OutlineItemPasteboardType, let dict = propertyList as? [String: String], let title = dict["title"] else { return nil } self.title = title super.init() } }
2. 实现数据源的粘贴板Writer方法
让outlineView(_:pasteboardWriterForItem:)返回对应条目的writer实例,NSOutlineView会自动将所有选中条目的writer添加到粘贴板,不会出现覆盖:
func outlineView(_ outlineView: NSOutlineView, pasteboardWriterForItem item: Any) -> NSPasteboardWriting? { guard let outlineItem = item as? OutlineItem else { return nil } return outlineItem }
3. 在接受拖放时读取所有条目
在outlineView(_:acceptDrop:item:childIndex:)中批量读取粘贴板内的所有条目,完成插入逻辑:
func outlineView(_ outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool { guard let pasteboard = info.draggingPasteboard, let items = pasteboard.readObjects(forClasses: [OutlineItem.self], options: nil) as? [OutlineItem] else { return false } // 插入到目标位置(需创建副本避免引用冲突) let parentItem = item as? OutlineItem ?? yourRootItem var insertionIndex = index for droppedItem in items { let newItem = OutlineItem(title: droppedItem.title) parentItem.children.insert(newItem, at: insertionIndex) insertionIndex += 1 } outlineView.reloadData() return true }
4. 配置拖放操作权限(可选)
实现代理方法设置允许的拖放操作类型:
func outlineView(_ outlineView: NSOutlineView, draggingSession session: NSDraggingSession, sourceOperationMaskFor context: NSDraggingContext) -> NSDragOperation { return .copy // 或 .move,根据业务需求调整 }
若之前出现粘贴板仅保留最后一个条目的问题,通常是因为数据模型未正确遵循粘贴板协议,或序列化逻辑导致同一类型数据被覆盖,按上述标准实现即可解决。
内容的提问来源于stack exchange,提问作者blackirishman
相关产品推荐
相关产品推荐

