如何给SwiftUI Table的行与列头添加自定义ContextMenu?
SwiftUI 3.0 Table 自定义上下文菜单实现方案
实现逻辑
- 行级上下文菜单:使用
TableColumn的自定义内容闭包,为每行的单元格视图绑定对应数据模型的专属菜单,同一行所有列绑定相同菜单即可保证行任意区域唤出菜单一致 - 列头上下文菜单:使用
TableColumn的header自定义闭包替换默认文本表头,为自定义表头视图添加专属上下文菜单,不会影响原有表头排序功能
完整可运行代码
import SwiftUI struct Person: Identifiable { let givenName: String let familyName: String let id = UUID() } struct TableContextMenuDemo: View { @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("名字", value: \.givenName) { person in Text(person.givenName) // 绑定当前行专属上下文菜单 .contextMenu { Button("编辑\(person.givenName)信息") { // 实现行编辑逻辑 } Button("删除\(person.givenName)", role: .destructive) { // 实现行删除逻辑 people.removeAll { $0.id == person.id } } } } .header { // 自定义列头,添加上下文菜单 Text("名字") .contextMenu { Button("隐藏该列") { // 实现列隐藏逻辑 } Button("升序排列") { sortOrder = [KeyPathComparator(\Person.givenName, order: .forward)] } Button("降序排列") { sortOrder = [KeyPathComparator(\Person.givenName, order: .reverse)] } } } TableColumn("姓氏", value: \.familyName) { person in Text(person.familyName) // 同一行绑定相同的上下文菜单 .contextMenu { Button("编辑\(person.givenName)信息") { // 实现行编辑逻辑 } Button("删除\(person.givenName)", role: .destructive) { people.removeAll { $0.id == person.id } } } } .header { Text("姓氏") .contextMenu { Button("隐藏该列") { // 实现列隐藏逻辑 } Button("按首字母排序") { sortOrder = [KeyPathComparator(\Person.familyName)] } } } } .onChange(of: sortOrder) { people.sort(using: $0) } } }
注意事项
- 同一行所有列的单元格视图必须绑定完全相同的上下文菜单,避免同一行不同位置唤出不同菜单的异常交互
- 自定义表头时不要添加独立的
tapGesture修饰符,会覆盖原生Table的点击表头排序手势
内容的提问来源于stack exchange,提问作者user1397892
相关产品推荐
相关产品推荐

