在Swift中实现拖放区域
我最近开始使用Swift构建OSX应用程序,我想知道如何实现拖放区 更具体地说,我构建了一个处理图像的应用程序,但目前,用户必须手动输入输入图像的路径或使用文件选择器(这很烦人)。我想改进我的应用程序,允许用户通过简单的拖放输入图像(我只需要检索表示图像路径的字符串)在Swift中实现拖放区域,swift,macos,cocoa,Swift,Macos,Cocoa,我最近开始使用Swift构建OSX应用程序,我想知道如何实现拖放区 更具体地说,我构建了一个处理图像的应用程序,但目前,用户必须手动输入输入图像的路径或使用文件选择器(这很烦人)。我想改进我的应用程序,允许用户通过简单的拖放输入图像(我只需要检索表示图像路径的字符串) 我如何才能做到这一点?下面是我在应用程序中使用的一个示例 如有必要,将对NSDraggingDestination的一致性添加到子类声明中(对于NSImageView不需要,因为它已经符合协议) 声明接受类型的数组(至少NSFil
我如何才能做到这一点?下面是我在应用程序中使用的一个示例
NSDraggingDestination
的一致性添加到子类声明中(对于NSImageView
不需要,因为它已经符合协议)NSFilenamesPboardType
)RegisterForDragedTypes
draggingEntered
,draggingUpdated
和performdraggoperation
nsdragooperation
draggingPasteboard
数组中获取文件路径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
}
}
Swift 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
}
}
Swift 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
}
}
此实现允许多个文件 只需在Interface Builder中将view类设置为
DragView
,在控制器中实现DragViewDeleteGate
,然后在Interface Builder中连接代理出口。这样,您将获得一个带有文件URL的委托回调
func-dragViewDidReceive(文件URL:[URL])
{
//耶!
}
DragView.swift
//
//斯威夫特
//
//版权所有(c)2020 Geri Borbáshttp://www.twitter.com/_eppz
//
//特此免费授予获得本软件及相关文档文件(“软件”)副本的任何人在不受限制的情况下经营本软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售本软件副本的权利,并允许向其提供软件的人员在符合以下条件的情况下这样做:
//上述版权声明和本许可声明应包含在软件的所有副本或实质部分中。
//本软件按“原样”提供,无任何明示或暗示的担保,包括但不限于适销性、特定用途适用性和非侵权性担保。在任何情况下,作者或版权持有人均不对任何索赔、损害赔偿或其他责任负责,无论是合同诉讼、侵权诉讼还是其他诉讼,均由本软件或本软件的使用或其他交易引起,或与本软件或本软件的使用或其他交易有关。
进口可可
@objc协议DragViewDelegate
{
func-dragViewDidReceive(文件URL:[URL])
}
类DragView:NSView
{
@IBV弱var委托:DragViewDelegate?
让fileExtensions=[“pdf”]
必需初始化?(编码器:NSCoder)
{
super.init(编码器:编码器)
颜色(至:。清除)
registerForDraggedTypes([.fileURL])
}
覆盖函数draggingEntered(uggininfo:NSDraggingInfo)->nsdragooperation
{
var containsMatchingFiles=false
DragginInfo.draggingPasteboard.readObjects(对于类:[NSURL.self],选项:nil)?.forEach
{
每个项目
如果让eachURL=eachObject作为?URL
{
containsMachingfiles=containsMachingfiles | | fileExtensions.contains(eachURL.pathExtension.lowercased())
如果包含smatchingfiles{print(eachURL.path)}
}
}
交换机(包含通讯文件)
{
大小写正确:
颜色(至:。secondaryLabelColor)
返回,收到
案例错误:
颜色(至:。disabledControlTextColor)
return.init()
}
}
重写func performDragOperation(ugginInfo:nsDragginInfo)->Bool
{
//收集URL。
var matchingfileurl:[URL]=[]
DragginInfo.draggingPasteboard.readObjects(对于类:[NSURL.self],选项:nil)?.forEach
{
每个项目
如果
让eachURL=eachObject作为?URL,
fileExtensions.contains(eachURL.pathExtension.lowercased())
{matchingfileurl.append(eachURL)}
}
//如果有的话,
guard matchingFileURLs.count>0
else{return false}
//传给代表。
委托?.dragViewDidReceive(文件URL:匹配文件URL)
返回真值
}
覆盖功能拖动退出(u发送方:NSDraggingInfo?)
{颜色(到:。清除)}
覆盖函数拖动(发送方:NSDraggingInfo)
{颜色(到:。清除)}
}
扩展DragView
{
func颜色(到颜色:NSColor)
{
self.wantsLayer=true
self.layer?.backgroundColor=color.cgColor
}
}
谢谢Eric D。Apple doc在这里:警告:NSURLPboardType在Swift 4中不再工作了,还有一个问题。如果您知道如何在Swift 4中使用NSURLPboardType和这些其他常量,请进行编辑或添加您自己的答案。谢谢。谢谢你的Swift 4版本。Xcode要求我在imagePath和path之前添加“let”,以使代码正常工作。