我需要能够将应用程序中包含的NSView的文件表示形式(在我的情况下为pdf)拖到桌面或支持打开PDF文件的其他应用程序上。
我花了几个小时试图在自己的应用程序中运行它,我想在这里添加我的解决方案,因为在线上有很多半解决方案,其中一些依赖于Obj-C扩展,而另一些则依赖于Obj-C扩展。已过时,不再受支持。我希望这篇文章能像我希望在自己的搜索中找到的那样。我也知道系统的所有细节(例如,使用文件协调器而不是直接写入),但这似乎是实现所需的最少代码。
我还提供了一个简单的Swift NSView实现。
该操作分为三个主要阶段。
您需要通过实现NSPasteboardItemDataProvider
协议,将视图(或其他控件)作为拖动的“数据提供程序”。所需的大部分工作(开始拖动除外)发生在以下协议功能中。
func pasteboard(_ pasteboard: NSPasteboard?, item _: NSPasteboardItem, provideDataForType type: NSPasteboard.PasteboardType)
此部分在拖动开始时发生。就我而言,我是在mouseDown()中执行此操作的,但是例如,您也可以在mouseDragged中执行此操作。
kPasteboardTypeFilePromiseContent
)提供文件类型UTIkPasteboardTypeFileURLPromise
)kPasteboardTypeFilePromiseContent
这是子站的接收者的第一个回调(通过pasteboard(pasteboard:item:provideDataForType:)
)
kPasteboardTypeFilePromiseContent
设置UTI(通过在粘贴板对象上使用setString(“”))来响应kPasteboardTypeFileURLPromise
这是接收方的第二个回调(通过pasteboard(pasteboard:item:provideDataForType:)
)接收方要求我们将数据写入磁盘上的文件。
com.apple.pastelocation
)的文件夹kPasteboardTypeFileURLPromise
设置写入文件的结果URL(使用粘贴板对象上的setString()来响应。请注意,此字符串的格式必须为file:///...
,因此需要使用.absoluteString()
。我们完成了!
// Some definitions to help reduce the verbosity of our code
let PasteboardFileURLPromise = NSPasteboard.PasteboardType(rawValue: kPasteboardTypeFileURLPromise)
let PasteboardFilePromiseContent = NSPasteboard.PasteboardType(rawValue: kPasteboardTypeFilePromiseContent)
let PasteboardFilePasteLocation = NSPasteboard.PasteboardType(rawValue: "com.apple.pastelocation")
class MyView: NSView {
override func mouseDown(with event: NSEvent) {
let pasteboardItem = NSPasteboardItem()
// (1, 2) Tell the pasteboard item that we will provide both file and content promises
pasteboardItem.setDataProvider(self, forTypes: [PasteboardFileURLPromise, PasteboardFilePromiseContent])
// Create the dragging item for the drag operation
let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)
draggingItem.setDraggingFrame(self.bounds, contents: image())
// Start the dragging session
beginDraggingSession(with: [draggingItem], event: event, source: self)
}
}
然后,在您的Pasteboard Item Data提供程序扩展中...
extension MyView: NSPasteboardItemDataProvider {
func pasteboard(_ pasteboard: NSPasteboard?, item _: NSPasteboardItem, provideDataForType type: NSPasteboard.PasteboardType) {
if type == PasteboardFilePromiseContent {
// The receiver will send this asking for the content type for the drop, to figure out
// whether it wants to/is able to accept the file type (3).
// In my case, I want to be able to drop a file containing PDF from my app onto
// the desktop or another app, so, add the UTI for the pdf (4).
pasteboard?.setString("com.adobe.pdf", forType: PasteboardFilePromiseContent)
}
else if type == PasteboardFileURLPromise {
// The receiver is interested in our data, and is happy with the format that we told it
// about during the kPasteboardTypeFilePromiseContent request.
// The receiver has passed us a URL where we are to write our data to (5).
// It is now waiting for us to respond with a kPasteboardTypeFileURLPromise
guard let str = pasteboard?.string(forType: PasteboardFilePasteLocation),
let destinationFolderURL = URL(string: str) else {
// ERROR:- Receiver didn't tell us where to put the file?
return
}
// Here, we build the file destination using the receivers destination URL
// NOTE: - you need to manage duplicate filenames yourself!
let destinationFileURL = destinationFolderURL.appendingPathComponent("dropped_file.pdf")
// Write your data to the destination file (6). Do better error handling here!
let pdfData = self.dataWithPDF(inside: self.bounds)
try? pdfData.write(to: destinationFileURL, options: .atomicWrite)
// And finally, tell the receiver where we wrote our file (7)
pasteboard?.setString(destinationFileURL.absoluteString, forType: PasteboardFileURLPromise)
}
}
[如果有人发现问题或完全不正确,请告诉我!它似乎至少对我的应用程序有效。
正如Willeke指出的,Apple有一些示例代码,用于使用(较新的)NSFilePromiseProvider机制进行拖放。
我希望我的搜索从Apple的Developer页面而不是Google started开始。那好吧!提供的示例有效并且仍然有效,因此,如果这篇文章可以帮助某人找到有关拖放的更多衔接信息,那就太棒了。