MacOS 开发(十六) : 文件拖拽

文件拖拽的核心是拖拽目标视图 (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
    }
}

你可能感兴趣的:(MacOS 开发(十六) : 文件拖拽)