Created
February 14, 2020 18:21
-
-
Save jmcd/ffd9be37fc48331b1d20a484d81bc0ee to your computer and use it in GitHub Desktop.
Checking out drag n' drop in Swift UI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct AnimalView: View { | |
var model: Animal | |
var body: some View { | |
VStack { | |
Image(systemName: model.systemImageName) | |
.resizable() | |
.scaledToFit() | |
.frame(width: 50, height: 50) | |
Text(model.name) | |
} | |
.onDrag { | |
NSItemProvider(object: self.model) | |
} | |
} | |
} | |
struct TrashView: View { | |
@EnvironmentObject var zoo: Zoo | |
var body: some View { | |
Image(systemName: "trash") | |
.resizable() | |
.scaledToFit() | |
.frame(width: 100, height: 100) | |
.onDrop(of: [Animal.typeIdentifier], isTargeted: nil) { ips in | |
guard let ip = ips.first(where: { ip in ip.hasItemConformingToTypeIdentifier(Animal.typeIdentifier) }) else { return false } | |
ip.loadObject(ofClass: Animal.self) { reading, _ in | |
guard let animal = reading as? Animal else { return } | |
DispatchQueue.main.async { | |
self.zoo.amimals.removeAll(where: { a in a.name == animal.name }) | |
} | |
} | |
return true | |
} | |
} | |
} | |
struct ContentView: View { | |
@ObservedObject var zoo = Zoo() | |
var body: some View { | |
HStack { | |
Spacer() | |
VStack { | |
ForEach(zoo.amimals, id: \.name) { animal in | |
AnimalView(model: animal) | |
} | |
} | |
Spacer() | |
TrashView().environmentObject(zoo) | |
} | |
} | |
} | |
struct ContentView_Previews: PreviewProvider { | |
static var previews: some View { | |
ContentView() | |
} | |
} | |
// MARK: - Model | |
class Zoo: ObservableObject { | |
@Published var amimals = [ | |
Animal(name: "Hare", systemImageName: "hare.fill"), | |
Animal(name: "Ant", systemImageName: "ant.fill"), | |
Animal(name: "Tortoise", systemImageName: "tortoise.fill"), | |
] | |
} | |
final class Animal: NSObject { | |
public static let typeIdentifier = "dnd.animal" | |
let name: String | |
let systemImageName: String | |
internal init(name: String, systemImageName: String) { | |
self.name = name | |
self.systemImageName = systemImageName | |
} | |
} | |
extension Animal: NSItemProviderReading { | |
static var readableTypeIdentifiersForItemProvider: [String] = [typeIdentifier] | |
static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Animal { | |
let components = String(data: data, encoding: .utf8)!.split(separator: ",").map(String.init) | |
return Animal(name: components[0], systemImageName: components[1]) | |
} | |
} | |
extension Animal: NSItemProviderWriting { | |
static var writableTypeIdentifiersForItemProvider: [String] = [typeIdentifier] | |
func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void) -> Progress? { | |
completionHandler("\(name),\(systemImageName)".data(using: .utf8), nil) // very terrible encoding and decoding 🙃 | |
let p = Progress(totalUnitCount: 1) | |
p.completedUnitCount = 1 | |
return p | |
} | |
} |
Hi juandahurt, Thanks for the reply.
As it turns out, I came back to the project after a couple of days, and now the "ips" parameter variable is populated correctly and the code works. I did not change any code, so I cannot explain why it was not working earlier. All good now. :-)
To any future people reading this, this example doesn't work building for macOS Big Sur, Xcode 12.5. You have to add "dnd.animal" as a UTType in your info.plist, you can see how to do that here.
Alternatively, you can just remove the "dnd.animal" and just swap it with a different UTType, I used "UTType.data" and everything worked ok
static let typeIdentifier = UTType.data
static var readableTypeIdentifiersForItemProvider: [String] = [typeIdentifier.identifier]
static var writableTypeIdentifiersForItemProvider: [String] = [typeIdentifier.identifier]
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What if you try to do an
if let ip = ips.first...