【发布时间】:2020-02-17 12:26:55
【问题描述】:
我想实现与 NSOutlineView 类似的 Mac Finder 应用程序的拖放。使用我当前的实现,拖放会话验证拖放到每个父母的孩子。我不想要那个。我只想将孩子从一个父母转移到另一个父母。就像在 Finder 中将文件从一个文件夹移动到另一个文件夹一样。怎么做?下面是包含我的拖放代码的示例代码。
import Cocoa
class ViewController: NSViewController {
@IBOutlet weak var outlineView: NSOutlineView!
private let treeController = NSTreeController()
@objc dynamic var content = [Node]()
override func viewDidLoad() {
super.viewDidLoad()
outlineView.delegate = self
outlineView.dataSource = self
treeController.objectClass = Node.self
treeController.childrenKeyPath = "children"
treeController.countKeyPath = "count"
treeController.leafKeyPath = "isLeaf"
outlineView.gridStyleMask = .solidHorizontalGridLineMask
outlineView.autosaveExpandedItems = true
treeController.bind(NSBindingName(rawValue: "contentArray"),
to: self,
withKeyPath: "content",
options: nil)
outlineView.bind(NSBindingName(rawValue: "content"),
to: treeController,
withKeyPath: "arrangedObjects",
options: nil)
content.append(contentsOf: NodeFactory().nodes())
outlineView.registerForDraggedTypes([.string])
outlineView.target = self
}
}
extension ViewController: NSOutlineViewDelegate, NSOutlineViewDataSource {
public func outlineView(_ outlineView: NSOutlineView,
viewFor tableColumn: NSTableColumn?,
item: Any) -> NSView? {
var cellView: NSTableCellView?
guard let identifier = tableColumn?.identifier else { return cellView }
switch identifier {
case .init("node"):
if let view = outlineView.makeView(withIdentifier: identifier,
owner: outlineView.delegate) as? NSTableCellView {
view.textField?.bind(.value,
to: view,
withKeyPath: "objectValue.value",
options: nil)
cellView = view
}
case .init("count"):
if let view = outlineView.makeView(withIdentifier: identifier,
owner: outlineView.delegate) as? NSTableCellView {
view.textField?.bind(.value,
to: view,
withKeyPath: "objectValue.childrenCount",
options: nil)
cellView = view
}
default:
return cellView
}
return cellView
}
func outlineView(_ outlineView: NSOutlineView, pasteboardWriterForItem item: Any) -> NSPasteboardWriting? {
let row = self.outlineView.row(forItem: item)
let pasteboardItem = NSPasteboardItem.init()
pasteboardItem.setString("\(row)", forType: .string)
return pasteboardItem
}
func outlineView(_ outlineView: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
if let node = (item as? NSTreeNode)?.representedObject as? Node {
if node.count >= 0 {
return .move
}
}
return .init(rawValue: 0)
}
}
@objc public class Node: NSObject {
@objc let value: String
@objc var children: [Node]
@objc var childrenCount: String? {
let count = children.count
guard count > 0 else { return nil }
return "\(count) node\(count > 1 ? "s" : "")"
}
@objc var count: Int {
children.count
}
@objc var isLeaf: Bool {
children.isEmpty
}
init(value: String, children: [Node] = []) {
self.value = value
self.children = children
}
}
final class NodeFactory {
func nodes() -> [Node] {
return [
.init(value: "???? Offers", children: [
.init(value: "???? Ice Cream"),
.init(value: "☕️ Coffee"),
.init(value: "???? Burger")
]),
.init(value: "Retailers", children: [
.init(value: "King Soopers"),
.init(value: "Walmart"),
.init(value: "Target"),
])
]
}
}
上述方法的当前结果:
预期结果:
【问题讨论】:
-
是什么阻止您在
outlineView(_:validateDrop:proposedItem:proposedChildIndex:)中实现此功能? -
@Willeke 用当前和预期的结果更新了我的问题
-
您必须进行一些编码,请发布您的尝试。提示:使用
collectionView(_:validateDrop:proposedIndexPath:dropOperation:)而不是collectionView(_:validateDrop:proposedIndex:dropOperation:)并查看文档。 -
@Willeke 我在问题中包含了故事板以外的部分代码。也将尝试包括在内。顺便说一句,我使用大纲视图而不是集合视图。
-
糟糕,又混淆了
NSCollectionsView和NSOutlineVIew。对不起。
标签: swift cocoa drag-and-drop nsoutlineview nstreecontroller