SwiftUI macOS 可双击编辑单元格的三列Table实现问题
macOS SwiftUI 三列可编辑Table实现方案(仿系统DNS样式)
问题修复与功能实现说明
1. 编辑状态TextField偏移修复
macOS下SwiftUI的TextField默认带有内边距和样式,导致和非编辑状态的Text对齐偏移。解决方案:
- 给TextField设置
textFieldStyle(.plain)移除默认样式 - 自定义padding匹配Table单元格的默认文本边距(如
EdgeInsets(top: 3, leading: 6, bottom: 3, trailing: 6)) - 用
frame(maxWidth: .infinity, alignment: .leading)确保文本左对齐,和非编辑状态一致
2. 整行高亮与加减按钮实现
- 整行高亮:通过给
Table绑定selection参数,配合TableRow的背景色自定义(或使用系统默认选中样式),实现单击选中整行并高亮 - 加减按钮:在Table同级放置按钮组,绑定数据数组的添加/删除逻辑,删除按钮根据选中状态动态禁用
完整实现代码
import SwiftUI struct DNSRecord: Identifiable { let id = UUID() var type: String var server: String var port: String } struct DNSTableView: View { @State private var records: [DNSRecord] = [ DNSRecord(type: "IPv4", server: "8.8.8.8", port: "53"), DNSRecord(type: "IPv6", server: "2001:4860:4860::8888", port: "53") ] @State private var selectedRecordId: DNSRecord.ID? @State private var editingCell: (DNSRecord.ID, String)? // 记录当前编辑的单元格(ID+字段名) var body: some View { VStack(spacing: 12) { Table(records, selection: $selectedRecordId) { TableColumn("类型") { record in cellContent(for: record, field: "type", value: record.type) } TableColumn("服务器") { record in cellContent(for: record, field: "server", value: record.server) } TableColumn("端口") { record in cellContent(for: record, field: "port", value: record.port) } } .tableStyle(.bordered) HStack(spacing: 16) { Button(action: addNewRecord) { Image(systemName: "plus") } Button(action: deleteSelectedRecord) { Image(systemName: "minus") } .disabled(selectedRecordId == nil) } .buttonStyle(.bordered) } .padding() .frame(minWidth: 600, minHeight: 400) } // 复用单元格内容视图,处理编辑/非编辑状态 private func cellContent(for record: DNSRecord, field: String, value: String) -> some View { Group { if editingCell == (record.id, field) { TextField("", text: Binding( get: { value }, set: { newValue in updateRecord(record.id, field: field, value: newValue) } )) .textFieldStyle(.plain) .padding(EdgeInsets(top: 3, leading: 6, bottom: 3, trailing: 6)) .onSubmit { editingCell = nil } .onExitCommand { editingCell = nil } } else { Text(value) .padding(EdgeInsets(top: 3, leading: 6, bottom: 3, trailing: 6)) .onTapGesture(count: 2) { editingCell = (record.id, field) } } } .frame(maxWidth: .infinity, alignment: .leading) } // 更新指定记录的字段值 private func updateRecord(_ id: DNSRecord.ID, field: String, value: String) { guard let index = records.firstIndex(where: { $0.id == id }) else { return } var record = records[index] switch field { case "type": record.type = value case "server": record.server = value case "port": record.port = value default: break } records[index] = record } // 添加新记录 private func addNewRecord() { records.append(DNSRecord(type: "", server: "", port: "53")) } // 删除选中记录 private func deleteSelectedRecord() { guard let selectedId = selectedRecordId else { return } records.removeAll { $0.id == selectedId } selectedRecordId = nil } } struct DNSTableView_Previews: PreviewProvider { static var previews: some View { DNSTableView() } }
代码关键点说明
- 用
editingCell元组精准控制单个单元格的编辑状态,双击单元格触发编辑 - TextField通过plain样式+自定义padding完全匹配非编辑状态的文本位置,解决偏移问题
- Table绑定
selection实现单击选中整行,系统默认提供高亮样式(可通过background修饰符自定义) - 加减按钮直接操作数据数组,删除按钮根据选中状态动态禁用,符合系统设置的交互逻辑
内容的提问来源于stack exchange,提问作者Danny
相关产品推荐
相关产品推荐

