2015-03-24 10 views
14

Ich habe Swift vor kurzem damit begonnen, OS X-Apps zu erstellen, und ich frage mich, wie ich eine Drag-and-Drop-Zone implementieren könnte.Implementieren einer Drag & Drop-Zone in Swift

Genauer gesagt, ich baute eine App, die Bilder verarbeitet, aber im Moment muss der Benutzer den Pfad zu den Eingabebildern manuell eingeben oder eine Dateiauswahl verwenden (was ziemlich ärgerlich ist). Ich möchte meine App verbessern, so dass der Benutzer die Bilder einfach per Drag-and-Drop eingeben kann (ich brauche nur einen String, der den Pfad zu den Bildern darstellt).

Wie kann ich das tun?

+0

https://developer.apple.com/library/mac/ Dokumentation/Kakao/Konzeptionell/D ragandDrop/Tasks/DraggingFiles.html –

Antwort

36

Hier ist ein Beispiel, das ich in einer Anwendung verwende.

  1. In Übereinstimmung mit NSDraggingDestination auf Ihre Unterklasse Erklärung, falls erforderlich (nicht für NSImageView benötigt, da es bereits mit dem Protokoll entspricht)
  2. Deklarieren Sie ein Array von akzeptierten Typen (mindestens NSFilenamesPboardType)
  3. diese Art Registrieren Sie sich bei registerForDraggedTypes
  4. Aufschalten draggingEntered, draggingUpdated und performDragOperation
  5. Liefert ein NSDragOperation von diesen Methoden
  6. Erhalten Sie die Datei (en) Pfad (e) aus der draggingPasteboard Array

In meinem Beispiel habe ich eine Funktion hinzugefügt haben, wenn die Dateierweiterung unter denen ist zu überprüfen, die wir wollen.

Swift 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 
    } 
} 

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 
    } 
} 
+0

Danke für deine Antwort! Es funktioniert gut – asonnino

+0

Danke Eric D. Und Apple Doc ist hier: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DragandDrop/Tasks/DraggingFiles.html –

+0

Warnung: NSURLPboardType funktioniert nicht mehr in Swift 4 und da ist [noch keine Lösung] (https://forums.developer.apple.com/thread/79144). Wenn Sie wissen, wie Sie NSURLPboardType und diese anderen Konstanten in Swift 4 verwenden, machen Sie eine Bearbeitung oder fügen Sie Ihre eigene Antwort hinzu. Vielen Dank. – Moritz

1

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 
    } 
} 
+0

Vielen Dank für die Swift 4-Version. Xcode hat mich gebeten, "let" vor imagePath und path hinzuzufügen, damit der Code funktioniert. – Cue

Verwandte Themen