Reputation: 113
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)
}
}
Upvotes: 9
Views: 2408
Reputation: 1953
It's an old question, but now it seems like this is easier to do. The below will show the uuid
of the person right-clicked anywhere on the Table
's row:
struct Person: Identifiable {
let givenName: String
var 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)
}.contextMenu(forSelectionType: UUID.self, menu: { items in
// The content of items will be the UUID of the selected people
Button("\(items.first!.uuidString)") {
dump(items)
}
}, primaryAction: { items in
// Do something when the user double-clicks if you want to
let i = (people.firstIndex(where: {aPerson in aPerson.id == items.first!}))!
people[i].familyName = "Smith"
})
}
Upvotes: 2
Reputation: 5320
From macOS 13 this will work as expected:
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)
}
}
}
Upvotes: 6
Reputation: 1517
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 })
}
}
Upvotes: 3