2015-03-24 18 views
14

Niedawno zacząłem używać Swift do budowania aplikacji OS X i zastanawiam się, w jaki sposób mogę zaimplementować strefę "przeciągnij i upuść".Wdrażanie strefy przeciągania i upuszczania w Swift

Dokładniej, stworzyłem aplikację, która przetwarza obrazy, ale na razie użytkownik musi ręcznie wprowadzić ścieżkę do obrazów wejściowych lub użyć selektora plików (co jest dość denerwujące). Chciałbym poprawić moją aplikację, pozwalając użytkownikowi na wprowadzanie obrazów za pomocą prostego przeciągania i upuszczania (potrzebuję tylko pobrać ciąg reprezentujący ścieżkę do obrazów).

Jak mogę to zrobić?

+0

https://developer.apple.com/library/mac/ dokumentacja/Cocoa/Conceptual/D ragandDrop/Tasks/DraggingFiles.html –

Odpowiedz

36

Oto przykład, którego używam w aplikacji.

  1. Dodaj zgodność z NSDraggingDestination do deklaracji podklasy, jeśli to konieczne (nie potrzebne NSImageView bo to już jest zgodny z protokołem)
  2. Zadeklaruj tablicę akceptowanych typów (przynajmniej NSFilenamesPboardType)
  3. zarejestrować te typy z registerForDraggedTypes
  4. Zastąp draggingEntered, draggingUpdated i performDragOperation
  5. zwróci NSDragOperation z tych metod
  6. Pobierz plik (s) Ścieżka (ów) z tablicy draggingPasteboard

w moim przykładzie dodałem funkcję, aby sprawdzić, czy rozszerzenie pliku jest wśród tych, których chcemy.

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

Dzięki za odpowiedź! Działa dobrze – asonnino

+0

Dzięki Eric D. A dokumentacja Apple jest tutaj: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DragandDrop/Tasks/DraggingFiles.html –

+0

Ostrzeżenie: NSURLPboardType już nie działa w Swift 4 i nie ma jeszcze rozwiązania (https://forums.developer.apple.com/thread/79144). Jeśli wiesz, jak używać NSURLPboardType i innych stałych w Swift 4, edytuj lub dodaj własną odpowiedź. Dzięki. – 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

Dziękujemy za wersję Swift 4. Xcode poprosił mnie o dodanie "let" przed imagePath i ścieżką, aby kod zadziałał. – Cue

Powiązane problemy