Основано на ответе Корбина (кстати, спасибо, что пролил свет на это):
Swift 3, NSTableView на основе представления с автоматическим макетом для MacOS 10.11 (и выше)
Моя настройка: у меня есть NSTableCellView
, который выложен с использованием Auto-Layout. Он содержит (помимо других элементов) многострочное NSTextField
, которое может иметь до 2 строк. Поэтому высота всего представления ячейки зависит от высоты этого текстового поля.
Я обновляю указание табличному виду обновлять высоту в двух случаях:
1) Когда размер таблицы изменяется:
func tableViewColumnDidResize(_ notification: Notification) {
let allIndexes = IndexSet(integersIn: 0..<tableView.numberOfRows)
tableView.noteHeightOfRows(withIndexesChanged: allIndexes)
}
2) Когда объект модели данных изменяется:
tableView.noteHeightOfRows(withIndexesChanged: changedIndexes)
Это заставит табличное представление запросить у своего делегата новую высоту строки.
func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
// Get data object for this row
let entity = dataChangesController.entities[row]
// Receive the appropriate cell identifier for your model object
let cellViewIdentifier = tableCellViewIdentifier(for: entity)
// We use an implicitly unwrapped optional to crash if we can't create a new cell view
var cellView: NSTableCellView!
// Check if we already have a cell view for this identifier
if let savedView = savedTableCellViews[cellViewIdentifier] {
cellView = savedView
}
// If not, create and cache one
else if let view = tableView.make(withIdentifier: cellViewIdentifier, owner: nil) as? NSTableCellView {
savedTableCellViews[cellViewIdentifier] = view
cellView = view
}
// Set data object
if let entityHandler = cellView as? DataEntityHandler {
entityHandler.update(with: entity)
}
// Layout
cellView.bounds.size.width = tableView.bounds.size.width
cellView.needsLayout = true
cellView.layoutSubtreeIfNeeded()
let height = cellView.fittingSize.height
// Make sure we return at least the table view height
return height > tableView.rowHeight ? height : tableView.rowHeight
}
Сначала нам нужно получить объект нашей модели для строки (entity
) и соответствующий идентификатор представления ячейки. Затем мы проверяем, создали ли мы уже представление для этого идентификатора. Для этого мы должны вести список с представлениями ячеек для каждого идентификатора:
// We need to keep one cell view (per identifier) around
fileprivate var savedTableCellViews = [String : NSTableCellView]()
Если ни один не сохранен, нам нужно создать (и кэшировать) новый. Мы обновляем представление ячейки с нашим объектом модели и говорим ему перестроить все на основе текущей ширины представления таблицы. Высота fittingSize
может быть использована в качестве новой высоты.