Swift Question

What replacement for UITableViewAutomaticDimension should I use to get the same effect in NSTableView?

In iOS projects I do something like that:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 30


and have nicely resizing cells.

What should I do to reproduce the same behaviour in macOS project?




Ok,
func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat
.

Should I configure my SubView (cell view) (that actually is NSView) twice...

In both methods -
heightOfRow
and
viewFor tableColumn
?

I heard about reusing of cells, but can it be done without nibs?

Anyway, if I doing so I get not quite the intended result.

Delegate/Datasource:

let items = ["second label",
"second label with alotoftext alotof...", // long line
"second label"]

func numberOfRows(in tableView: NSTableView) -> Int {
return 3
}

func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
let cell = SubView(text: items[row])
cell.layoutSubtreeIfNeeded()
return cell.frame.size.height
}

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
return SubView(text: items[row])
}


SubView:

init(text: String) {
super.init(frame: CGRect.zero)

let text1 = NSTextField(labelWithString: "first label")
let text2 = NSTextField(labelWithString: text)

text2.lineBreakMode = .byWordWrapping
text2.setContentCompressionResistancePriority(100, for: .horizontal)

self.addSubview(text1)
self.addSubview(text2)

text1 <- [Top(5), Left(5), Right(5)]
text2 <- [Top(0).to(text1, .bottom), Left(5), Right(5), Bottom(5)]

}


Last two lines are EasyPeasy constraints.

So, result is: wrong

Where is my mistake?




And just one more question: what should I do to make cells grow/decrease vertically to fit all subviews inside of them accordingly to resizing width of tableView?

Oh, seem to have realized.

Just added the observer:

name: NSNotification.Name.NSViewFrameDidChange,
object: self.scrollView


And

let vr = scrollView.contentView.visibleRect
let indexes = tableView.rows(in: vr).toRange()!
tableView.noteHeightOfRows(withIndexesChanged: IndexSet(indexes))


in selector method.




Yep. The same view (SubView) works perfect without tableView.


But I still have the above-described problem with wrong-sized cellViews.

P.S.: Sorry for my english, I hope everything is clear.

Answer

On macOS it is a little more difficult, but not really hard to do. There is an excellent answer on this by corbin dunn, the author of NSTableView here.

To put it in a nutshell:
You need to know the size of your cell and return that value in

func tableView(NSTableView, heightOfRow: Int)

which is a method from NSTableViewDelegate.

Update 20.11.2016:

You are almost there! The view you create has no width set. So I guess that the view itself assumes that it is much narrower than the tableView and therefore higher.

func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
    let cell = SubView(text: items[row])
    cell.frame.size.width = tableView.frame.size.width
    cell.layoutSubtreeIfNeeded()
    return cell.frame.size.height
}

I have not tested this code but it should be it.