You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 10:06:03