这也困扰着我,因此我创建了一个示例项目并将其上传到GitHub。(
点击此处)
如@ben-rhayader所指出的那样,重点在于将字段编辑器放置在标题视图单元格上方。
双击处理
以下是我们已经知道的有关Swift的信息。
窗口控制器/自定义表格视图控制器
视图控制器中有趣的部分是双击编辑标题。要实现这一点:
- 将TableWindowController(或您的视图控制器)实例作为对象放入Nib中,
- 添加@IBAction func tableViewDoubleClick(sender: NSTableView)或类似方法,
- 将NSTableView的doubleAction方法连接到tableViewDoubleClick。
编辑单元格很简单。编辑列标题则不太容易。
- 标题行的行值为-1,
- 要定位字段编辑器,您需要列标题框架和字段编辑器本身。
结果的一部分:
extension TableWindowController {
@IBAction func tableViewDoubleClick(sender: NSTableView) {
let column = sender.clickedColumn
let row = sender.clickedRow
guard column > -1 else { return }
if row == -1 {
editColumnHeader(tableView: sender, column: column)
return
}
editCell(tableView: sender, column: column, row: row)
}
private func editColumnHeader(tableView tableView: NSTableView, column: Int) {
guard column > -1,
let tableColumn = tableView.tableColumn(column: column),
headerView = tableView.headerView as? TableHeaderView,
headerCell = tableColumn.headerCell as? TableHeaderCell,
fieldEditor = fieldEditor(object: headerView)
else { return }
headerCell.edit(
fieldEditor: fieldEditor,
frame: headerView.paddedHeaderRect(column: column),
headerView: headerView)
}
private func editCell(tableView tableView: NSTableView, column: Int, row: Int) {
guard row > -1 && column > -1,
let view = tableView.viewAtColumn(column, row: row, makeIfNecessary: true) as? NSTableCellView
else { return }
view.textField?.selectText(self)
}
func fieldEditor(object object: AnyObject?) -> NSText? {
return self.window?.fieldEditor(true, forObject: object)
}
}
自定义表头视图和表头视图单元格
正确定位字段编辑器需要一些工作。我将其放入了一个NSTableHeaderView
子类中:
class TableHeaderView: NSTableHeaderView {
struct Padding {
static let Vertical: CGFloat = 4
static let Right: CGFloat = 1
}
func paddedHeaderRect(column column: Int) -> NSRect {
let paddedVertical = CGRectInset(self.headerRectOfColumn(column), 0, Padding.Vertical)
let paddedRight = CGRect(
origin: paddedVertical.origin,
size: CGSize(width: paddedVertical.width - Padding.Right, height: paddedVertical.height))
return paddedRight
}
}
现在定位字段编辑器已经处理完毕。现在从上面的双击处理程序中使用它:
class TableHeaderCell: NSTableHeaderCell, NSTextViewDelegate {
func edit(fieldEditor fieldEditor: NSText, frame: NSRect, headerView: NSView) {
let endOfText = (self.stringValue as NSString).length
self.highlighted = true
self.selectWithFrame(frame,
inView: headerView,
editor: fieldEditor,
delegate: self,
start: endOfText,
length: 0)
fieldEditor.backgroundColor = NSColor.whiteColor()
fieldEditor.drawsBackground = true
}
func textDidEndEditing(notification: NSNotification) {
guard let editor = notification.object as? NSText else { return }
self.title = editor.string ?? ""
self.highlighted = false
self.endEditing(editor)
}
}
如何在用户双击其他标题单元格时“结束编辑”?
问题:当用户双击其他标题单元格时,字段编辑器将被重用并仅被重新定位。 textDidEndEditing
不会被调用。新值将不会被保存。
@triple.s 和 @boyfarrell 讨论过此问题,但没有提供代码 -- 我发现最简单的方法是劫持字段编辑器的构造并手动调用 endEditing
以知道何时字段编辑器将更改。
class HeaderFieldEditor: NSTextView {
func switchEditingTarget() {
guard let cell = self.delegate as? NSCell else { return }
cell.endEditing(self)
}
}
必要时使用此自定义字段编辑器:
class TableWindowController: NSWindowDelegate {
func windowWillReturnFieldEditor(sender: NSWindow, toObject client: AnyObject?) -> AnyObject? {
guard client is TableHeaderView else { return nil }
headerFieldEditor.switchEditingTarget()
return headerFieldEditor
}
lazy var headerFieldEditor: HeaderFieldEditor = {
let editor = HeaderFieldEditor()
editor.fieldEditor = true
return editor
}()
}
非常好用。
Github上的项目链接:https://github.com/DivineDominion/Editable-NSTableView-Header