这也困扰着我,所以我创建了一个示例项目并将其上传到 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)
}
/// Convenience accessor to the `window`s field editor.
func fieldEditor(object object: AnyObject?) -> NSText? {
return self.window?.fieldEditor(true, forObject: object)
}
}
自定义标题视图和标题视图单元格
正确定位字段编辑器是一项工作。我把它放到一个NSTableHeaderView
子类中:
class TableHeaderView: NSTableHeaderView {
/// Trial and error result of the text frame that fits.
struct Padding {
static let Vertical: CGFloat = 4
static let Right: CGFloat = 1
}
/// By default, the field editor will be very high and thus look weird.
/// This scales the header rect down a bit so the field editor is put
/// truly in place.
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? {
// Return default field editor for everything not in the header.
guard client is TableHeaderView else { return nil }
// Comment out this line to see what happens by default: the old header
// is not deselected.
headerFieldEditor.switchEditingTarget()
return headerFieldEditor
}
lazy var headerFieldEditor: HeaderFieldEditor = {
let editor = HeaderFieldEditor()
editor.fieldEditor = true
return editor
}()
}
奇迹般有效。
GitHub 上的项目:https ://github.com/DivineDominion/Editable-NSTableView-Header