iosswiftmacosswiftui

How to use Transferable for Table Rows in SwiftUI


With WWDC 2022, Apple introduced the Transferable protocol to support Drag & Drop operations in an easy way. How can I use this new technique (in combination with the new draggable and dropDestination modifiers) for SwiftUI tables (not lists)?

The TableRowContent does not support the draggable and dropDestination modifiers. Also, when applying the modifiers directly to the views in the TableColumns, the drag / drop operation will only work on for that specific cell, and not the entire row. When adding the modifiers to all cells, it still does not work when dragging e.g. in an empty space inside of a row.

struct Item: Identifiable, Codable, Transferable {
    let id = UUID()
    let text: String

    static var transferRepresentation: some TransferRepresentation {
        CodableRepresentation(contentType: .text)
    }
}

struct Test: View {
    var body: some View {
        Table {
            TableColumn("Column 1") { item in
                Text(item.text)
                    .draggable(item) // This does only work when dragging not in the space between two columns
            }
            TableColumn("Column 2") { item in
                Text(item.text)
                    .draggable(item) // This does only work when dragging not in the space between two columns
            }
        } rows: {
            ForEach([Item(text: "Hello"), Item(text: "World")]) { item in
                TableRow(item)
                    .draggable(item) // This causes a compile-time error
                    .itemProvider { ... } // This does not work with Transferable and thus support my use case
            }
        }
    }
}

I want a similar behavior as the itemProvider modifier and the recently added contextMenu modifier on the TableRowContent , which allow the respective operation on the whole table row. I cannot use itemProvider, since it requires to return an NSItemProvider, which does not support my use case of dragging a file from a network drive to the Mac hard drive.


Solution

  • With newer versions of SwiftUI, it's now possible to use the draggable(_:) modifier on a TableRow directly.