Get SwiftUI Table single-clicked (column, row) pair on macOS

When user single-clicks a SwiftUI Table
on macOS, I'd like to know the clicked (column, row) pair, or point. I added onTapGesture()
handler to the Table
, but it's never invoked. How can I figure out which (column, row) was clicked?
My goal is to implement cell selection in my view model. I need to be able to determine the clicked (column, row) pair in order to select the correct cell in the view model.
Below is Apple example code, to which I added the ineffective onTapGesture()
handler.
struct Person: Identifiable {
let givenName: String
let familyName: String
let emailAddress: String
let id = UUID()
}
struct PeopleTable: View {
@State private var people = [
Person(givenName: "Juan", familyName: "Chavez", emailAddress: "Read more"),
Person(givenName: "Mei", familyName: "Chen", emailAddress: "[email protected]"),
Person(givenName: "Tom", familyName: "Clark", emailAddress: "[email protected]"),
Person(givenName: "Gita", familyName: "Kumar", emailAddress: "[email protected]")
]
var body: some View {
Table(people) {
TableColumn("Given Name", value: \.givenName)
TableColumn("Family Name", value: \.familyName)
TableColumn("E-Mail Address", value: \.emailAddress)
}
.onTapGesture(perform: { p in
print("clicked point \(p)")
})
}
}
#Preview {
PeopleTable()
}
Answer
Pass a View
to the TableColumn
s, and add the tap gesture to that.
Table(people) {
TableColumn("Given Name") { person in
Text(person.givenName)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.contentShape(.rect)
.onTapGesture {
print("Clicked given name of \(person.id)")
}
}
TableColumn("Family Name") { person in
Text(person.familyName)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.contentShape(.rect)
.onTapGesture {
print("Clicked family name of \(person.id)")
}
}
TableColumn("E-Mail Address") { person in
Text(person.emailAddress)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.contentShape(.rect)
.onTapGesture {
print("Clicked email address of \(person.id)")
}
}
}
I have used frame
and contentShape
to increase the tappable as much as possible. Without those, the empty parts of the table cells are not tappable.
If this is still unsatisfactory, I would recommend wrapping a NSTableView
with a NSViewRepresentable
. You would set its action
to a method, then access clickedColumn
and clickedRow
in that method.
Enjoyed this article?
Check out more content on our blog or follow us on social media.
Browse more articles