Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drag and drop with custom type identifier doesn't work

Tags:

macos

swiftui

I'm trying to achieve drag and drop on macOS with a custom type identifier to avoid collisions but it doesn't seem to work. First, here's a working example with a public and known identifier:

struct ReleaseView: View {
    let id: Int

    var body: some View {
        GeometryReader { _ in
            VStack(spacing: 16) {
                Image(nsImage: NSImage(named: NSImage.networkName)!)
                    .contentShape(Rectangle())
                    .onDrag {
                        return NSItemProvider(item: "\(self.id)" as NSString, typeIdentifier: NSPasteboard.PasteboardType.string.rawValue)
                    }

                DropZone()
            }
        }
    }
}

struct DropZone: View {
    @State var isDragging = false

    var body: some View {
        RoundedRectangle(cornerRadius: 16)
            .stroke(style: StrokeStyle(lineWidth: 4, dash: [8, 8]))
            .background(isDragging ? Color.secondary : Color.clear)
            .frame(width: 100, height: 100)
            .onDrop(of: [NSPasteboard.PasteboardType.string.rawValue], isTargeted: self.$isDragging) { itemProvider in
                print(itemProvider)
                return true
            }
    }
}

In this example, you can drag the image above into the drop zone and it will print out the provider. Now, merely changing the typeIdentifier breaks everything.

static let sharedTypeIdentifier = "com.procrastin8.plzwork"

struct ReleaseView: View {
    // skipping the unchanged bits

                    .onDrag {
                        return NSItemProvider(item: "\(self.id)" as NSString, typeIdentifier: sharedTypeIdentifier)
                    }
}

struct DropZone: View {
    // skipping the unchanged bits

           .onDrop(of: [sharedTypeIdentifier], isTargeted: self.$isDragging) { itemProvider in
                print(itemProvider)
                return true
            }
}

Now this doesn't work. Using the same constant here, so it's not a string mismatch. Just yet another SwiftUI bug?

like image 570
Procrastin8 Avatar asked Apr 15 '20 09:04

Procrastin8


Video Answer


2 Answers

The typeIdentifier in above is not just a unique string, it must be UTI.

If you want to use some custom-application-specifc UTI (think twice if you really need it), then you have to register one according to Apple rules, starting from

<key>UTExportedTypeDeclarations</key>
        <array>
            <dict>
                <key>UTTypeIdentifier</key>
                <string>com.procrastin8.plzwork</string>
                ...

in app Info.plist

See details specifically in Declaring New Uniform Type Identifiers

And wide collection in Technical Q&A QA1796

like image 200
Asperi Avatar answered Oct 17 '22 21:10

Asperi


Nowadays, you can add a type identifier through target project and it adds the UTI string automatically on the Info.plist, as explained on this Raywenderlich article.


Walkthrough

  1. Select the project on Project Navigator
  2. Select the project target under "Targets" section
  3. Select the "Info" tab
  4. Expand "Exported Type Identifiers"
  5. Click + to add a new UTI
  6. Enter a description for the Description field
  7. Enter your identifier for the Identifier field with the same value you used in your code
  8. Under Conforms To enter public.data
like image 1
Mushu Avatar answered Oct 17 '22 22:10

Mushu