6

I found that the new table component of SwiftUI 3.0 is like a toy, which can be used easily, but it is difficult to expand more functions.

TableRow and TableColumn inherit from the value object. How can I get the view of a row? I want to set a different ContextMenu for each row. In addition, I want to set the ContextMenu for the column header.

How to implement it on the basis of Table component? I don't want to use the List component.

struct Person: Identifiable {

let givenName: String

let familyName: String

let id = UUID()

}

@State private var people = [

Person(givenName: "Juan", familyName: "Chavez"),

Person(givenName: "Mei", familyName: "Chen"),

Person(givenName: "Tom", familyName: "Clark"),

Person(givenName: "Gita", familyName: "Kumar"),

]

@State private var sortOrder = [KeyPathComparator(\Person.givenName)]

var body: some View {

Table(people, sortOrder: $sortOrder) {

TableColumn("Given Name", value: \.givenName)

TableColumn("Family Name", value: \.familyName)

}

.onChange(of: sortOrder) {

people.sort(using: $0)

}

}
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83

2 Answers2

3

In order to have contextMenu working on SwiftUI 3.0 Table it is necessary to add it to every TableColumn item. Plus, if you want to add Double Tap support it is necessary to add it independently too.

Table(documents, selection: $fileSelection) {
    TableColumn("File name") { item in
        Text(item.filename)
            .contextMenu { YOUR_CONTEXT_MENU }
            .simultaneousGesture(TapGesture(count: 1).onEnded { fileSelection = item.id })
            .simultaneousGesture(TapGesture(count: 2).onEnded { YOUR_DOUBLE_TAP_IMPLEMENTATION })
    }
    TableColumn("Size (MB)") { item in
        Text(item.size)
            .contextMenu { YOUR_CONTEXT_MENU }
            .simultaneousGesture(TapGesture(count: 1).onEnded { fileSelection = item.id })
            .simultaneousGesture(TapGesture(count: 2).onEnded { YOUR_DOUBLE_TAP_IMPLEMENTATION })
    }
}
AlbertUI
  • 1,409
  • 9
  • 26
  • 2
    Thank you for your reply, but this implementation can only work on the content of the cell, cannot completely cover the content of the whole line, and will not take effect for the blank part of the line. – user1397892 Nov 22 '21 at 03:53
  • 1
    @user1397892 I agree, is there any better solution by now? – DeveloBär Jan 27 '22 at 00:12
2

From macOS 13 this will work as expected:

enter image description here

To try it out use the Garden App from apple and replace the row section of the Table as below

  } rows: {
        
        ForEach(plants) { plant in
            TableRow(plant)
                .itemProvider { plant.itemProvider }
                .contextMenu {
                    Button {
                        
                    } label: {
                        Text("test")
                    }
                }
        }
        .onInsert(of: [Plant.draggableType]) { index, providers in
            Plant.fromItemProviders(providers) { plants in
                garden.plants.insert(contentsOf: plants, at: index)
            }
        }
    }
Marc T.
  • 5,090
  • 1
  • 23
  • 40