在Swift中实现拖放区域

aso*_*ino 17 macos cocoa swift

我最近开始使用Swift来构建OS X应用程序,我想知道如何实现拖放区域.

更具体地说,我构建了一个处理图像的应用程序,但目前用户必须手动输入输入图像的路径或使用文件选择器(这非常烦人).我想改进我的应用程序,允许用户通过简单的拖放输入图像(我只需要检索表示图像路径的字符串).

我怎样才能做到这一点?

aya*_*aio 38

这是我在应用程序中使用的一个示例.

  1. NSDraggingDestination如有必要,可以在子类声明中添加一致性(NSImageView因为它已经符合协议,所以不需要)
  2. 声明一个接受类型的数组(至少NSFilenamesPboardType)
  3. 注册这些类型 registerForDraggedTypes
  4. 覆盖draggingEntered,draggingUpdatedperformDragOperation
  5. NSDragOperation从这些方法中返回一个
  6. draggingPasteboard数组中获取文件路径

在我的例子中,我添加了一个函数来检查文件扩展名是否属于我们想要的扩展名.

斯威夫特2

class MyImageView: NSImageView {

    override func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        // Declare and register an array of accepted types
        registerForDraggedTypes([NSFilenamesPboardType, NSURLPboardType, NSPasteboardTypeTIFF])
    }

    let fileTypes = ["jpg", "jpeg", "bmp", "png", "gif"]
    var fileTypeIsOk = false
    var droppedFilePath: String?

    override func draggingEntered(sender: NSDraggingInfo) -> NSDragOperation {
        if checkExtension(sender) {
           fileTypeIsOk = true
           return .Copy
        } else {
           fileTypeIsOk = false
           return .None
        }
    }

    override func draggingUpdated(sender: NSDraggingInfo) -> NSDragOperation {
        if fileTypeIsOk {
            return .Copy
        } else {
            return .None
        }
    }

    override func performDragOperation(sender: NSDraggingInfo) -> Bool {
        if let board = sender.draggingPasteboard().propertyListForType("NSFilenamesPboardType") as? NSArray,
            imagePath = board[0] as? String {
            // THIS IS WERE YOU GET THE PATH FOR THE DROPPED FILE
            droppedFilePath = imagePath
            return true
        }
        return false
    }

    func checkExtension(drag: NSDraggingInfo) -> Bool {
        if let board = drag.draggingPasteboard().propertyListForType("NSFilenamesPboardType") as? NSArray,
            path = board[0] as? String {
            let url = NSURL(fileURLWithPath: path)
            if let fileExtension = url.pathExtension?.lowercaseString {
                return fileTypes.contains(fileExtension)
            }
        }
        return false
    }
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特3

class MyImageView: NSImageView {

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        // Declare and register an array of accepted types
        register(forDraggedTypes: [NSFilenamesPboardType, NSURLPboardType, NSPasteboardTypeTIFF])
    }

    let fileTypes = ["jpg", "jpeg", "bmp", "png", "gif"]
    var fileTypeIsOk = false
    var droppedFilePath: String?

    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        if checkExtension(drag: sender) {
            fileTypeIsOk = true
            return .copy
        } else {
            fileTypeIsOk = false
            return []
        }
    }

    override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation {
        if fileTypeIsOk {
            return .copy
        } else {
            return []
        }
    }

    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
        if let board = sender.draggingPasteboard().propertyList(forType: "NSFilenamesPboardType") as? NSArray,
            imagePath = board[0] as? String {
            // THIS IS WERE YOU GET THE PATH FOR THE DROPPED FILE
            droppedFilePath = imagePath
            return true
        }
        return false
    }

    func checkExtension(drag: NSDraggingInfo) -> Bool {
        if let board = drag.draggingPasteboard().propertyList(forType: "NSFilenamesPboardType") as? NSArray,
            path = board[0] as? String {
            let url = NSURL(fileURLWithPath: path)
            if let fileExtension = url.pathExtension?.lowercased() {
                return fileTypes.contains(fileExtension)
            }
        }
        return false
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 警告:NSURLPboardType 在 Swift 4 中不再工作,并且[尚无解决方案](https://forums.developer.apple.com/thread/79144)。如果您知道如何在 Swift 4 中使用 NSURLPboardType 和这些其他常量,请进行编辑或添加您自己的答案。谢谢。 (2认同)

kau*_*uai 8

斯威夫特4

class MyImageView: NSImageView {

    let NSFilenamesPboardType = NSPasteboard.PasteboardType("NSFilenamesPboardType")

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        // Declare and register an array of accepted types
        registerForDraggedTypes([NSPasteboard.PasteboardType(kUTTypeFileURL as String),
                                 NSPasteboard.PasteboardType(kUTTypeItem as String)])
    }

    let fileTypes = ["jpg", "jpeg", "bmp", "png", "gif"]
    var fileTypeIsOk = false
    var droppedFilePath: String?

    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        if checkExtension(drag: sender) {
            fileTypeIsOk = true
            return .copy
        } else {
            fileTypeIsOk = false
            return []
        }
    }

    override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation {
        if fileTypeIsOk {
            return .copy
        } else {
            return []
        }
    }

    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
        if let board = sender.draggingPasteboard().propertyList(forType: NSFilenamesPboardType) as? NSArray,
            imagePath = board[0] as? String {
            // THIS IS WERE YOU GET THE PATH FOR THE DROPPED FILE
            droppedFilePath = imagePath
            return true
        }
        return false
    }

    func checkExtension(drag: NSDraggingInfo) -> Bool {
        if let board = drag.draggingPasteboard().propertyList(forType: NSFilenamesPboardType) as? NSArray,
            path = board[0] as? String {
            let url = NSURL(fileURLWithPath: path)
            if let fileExtension = url.pathExtension?.lowercased() {
                return fileTypes.contains(fileExtension)
            }
        }
        return false
    }
}
Run Code Online (Sandbox Code Playgroud)