文件拖拽的核心是拖拽目标视图 (DragDestinationView),此方法会检测目标是否可拖拽类型,拖拽文件信息,图像会返回 image,颜色返回 Color,docx,ppt,zip 等返回路径(URL)。
import Cocoa
import CocoaExpand
@objc protocol DragDestinationViewDelegate: NSObjectProtocol {
@objc optional func processImage(_ image: NSImage, pasteBoard: NSPasteboard)
@objc optional func process(_ obj: Any, pasteBoard: NSPasteboard)
}
///拖拽目标视图
@available(macOS 10.13, *)
class DragDestinationView: NSView {
var delegate: DragDestinationViewDelegate?
///支持拖入的类型
var supportedTypes: [NSPasteboard.PasteboardType] = [.tiff, .color, .string, .fileURL, .html]{
willSet{
self.registerForDraggedTypes(newValue)
}
}
///支持拖入的子类型
var acceptableUTITypes: [NSPasteboard.ReadingOptionKey : Any] {
let types = [NSImage.imageTypes,
NSString.readableTypeIdentifiersForItemProvider,
NSURL.readableTypeIdentifiersForItemProvider].flatMap { $0 }
return [NSPasteboard.ReadingOptionKey.urlReadingContentsConformToTypes : types]
}
var isReceivingDrag = false {
didSet {
needsDisplay = true
}
}
// MARK: -lifecycle
convenience init(types: [NSPasteboard.PasteboardType]) {
self.init()
self.registerForDraggedTypes(types)
}
// MARK: -drag
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
return .copy
}
override func draggingExited(_ sender: NSDraggingInfo?) {
isReceivingDrag = false
}
override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
return true
}
// //仅支持 image 可用此方法
// override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
//
// isReceivingDrag = false
// let pasteBoard = sender.draggingPasteboard
// guard let image = NSImage(pasteboard: pasteBoard) else {
// return false
// }
// delegate?.processImage?(image, pasteBoard: pasteBoard)
// return true
// }
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
isReceivingDrag = false
let pasteBoard = sender.draggingPasteboard
let classArray: [AnyClass] = [NSImage.self, NSColor.self, NSString.self, NSURL.self]
return pasteBoard.readObjects(forClasses: classArray, options: acceptableUTITypes) { (obj) in
if let value = obj as? NSImage {
self.delegate?.processImage?(value, pasteBoard: pasteBoard)
} else {
self.delegate?.process?(obj, pasteBoard: pasteBoard)
}
}
}
override func concludeDragOperation(_ sender: NSDraggingInfo?) {
}
}
public extension NSPasteboard{
///获取拖拽元素的信息
@available(OSX 10.13, *)
var propertyList: [Any]? {
if let board = self.propertyList(forType: NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as? [String] {
print("FILE: \(board)")
return board
}
if let board = self.propertyList(forType: .URL) as? [URL] {
print("URL: \(board)")
return board
}
if let board = self.propertyList(forType: .string) as? [String] {
print("STRING: \(board)")
return board
}
if let board = self.propertyList(forType: .html) as? [String] {
print("HTML: \(board)")
return board
}
return nil
}
///拖拽的本地文件路径
@available(OSX 10.13, *)
var draggedFileURL: NSURL? {
if let property = propertyList?.first as? String {
print(property)
return NSURL(fileURLWithPath: property)
}
return nil
}
///解析拖拽到目标视图上的信息同时options 参数限制可拖入子元素的类型( nil 表示不限类型)
func readObjects(forClasses classArray: [AnyClass] = [NSImage.self, NSColor.self, NSString.self, NSURL.self],
options: [NSPasteboard.ReadingOptionKey : Any]? = nil,
handler: ((Any)->Void)? = nil) -> Bool {
guard let pasteboardObjects = readObjects(forClasses: classArray, options: options),
pasteboardObjects.count > 0 else {
return false
}
pasteboardObjects.forEach { (obj) in
switch obj {
case let value as NSImage:
print(#function, #line, "NSImage", value)
handler?(value)
case let value as NSString:
print(#function, #line, "NSString", value)
handler?(value)
case let value as NSColor:
print(#function, #line, "NSColor", value)
handler?(value)
case let value as URL:
print(#function, #line, "URL", value.absoluteString.removingPercentEncoding ?? "")
if let image = NSImage(contentsOfFile: value.path) {
print(#function, #line, image)
handler?(image)
} else {
handler?(value)
}
default:
print(#function, #line, obj)
handler?(obj)
break
}
}
return true
}
}
网友评论