Re: Auto-sized table cells, for macOS
Re: Auto-sized table cells, for macOS
- Subject: Re: Auto-sized table cells, for macOS
- From: Daryle Walker <email@hidden>
- Date: Fri, 17 Mar 2017 04:45:04 -0400
> On Mar 14, 2017, at 11:33 PM, Quincey Morris <email@hidden> wrote:
>
> On Mar 14, 2017, at 18:26 , Daryle Walker <email@hidden <mailto:email@hidden>> wrote:
>>
>> You’d think that this would be a solved problem….
>
> It sort of is. I think you can find a solution on stackoverflow.com <http://stackoverflow.com/> (which is where I got the idea from IIRC) but you have to wade through the out of date stuff to pick out a modern way of doing it. Here’s the code I came up with (for an outline view, table view should be similar):
I meant from the people at Apple HQ. Besides those who intentionally want truncating behavior, wouldn’t “expand to show all text” be the expected default? The current default isn’t friendly to end users.
>> func resizeListItem (_ listItem: RecentObjectValue, cell: NSTableCellView, width: CGFloat, resizedRows: NSMutableIndexSet? = nil)
>> {
>> cell.objectValue = listItem
>>
>> cell.textField?.preferredMaxLayoutWidth = width - 2
>> cell.needsUpdateConstraints = true
>> cell.layoutSubtreeIfNeeded ()
>>
>> let rowHeight = cell.fittingSize.height
>>
>> guard listItem.rowHeight != rowHeight else { return }
>>
>> listItem.rowHeight = rowHeight
>> let row = recentsListView.row (forItem: listItem)
>>
>> guard row >= 0, let rows = resizedRows else { return }
>>
>> rows.add (row)
>> }
>
> The listItem parameter is a custom struct that contains the actual data displayed in the row (the data model of the outline view, in effect), but it also caches the row height. The resizedRows parameter just accumulates an optional set of changed heights for a subsequent “noteHeightOfRowsChanged”. The cell parameter is created once for measuring purposes, in viewDidLoad:
>
>> /* view controller instance variable */ headerCell = recentsListView.make (withIdentifier: "HeaderCell", owner: self) as! NSTableCellView
>> let headerConstraint = NSLayoutConstraint (item: headerCell, attribute: .height, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 17)
>> NSLayoutConstraint.activate ([headerConstraint])
>
> The only other thing you need is a strategy for deciding when to recalculate the heights. When the column width changes, obviously, as well as for inserted rows, but there might be other cases as well.
Unfortunately, you didn’t provide your Stack Overflow sources. I made my first attempt after reading <http://stackoverflow.com/a/32332743/1010226>:
> // Increase the row height to fit all the text (instead of the first line).
> func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
> precondition(tableView === self.headerTableView)
>
> var height = tableView.rowHeight
> let nameColumn = tableView.tableColumn(withIdentifier: Names.nameColumnIdentifier)!
> let bodyColumn = tableView.tableColumn(withIdentifier: Names.bodyColumnIdentifier)!
> let field = (self.headerArrayController.arrangedObjects as! NSArray).object(at: row) as! RawHeaderField
> let attributes = [NSFontAttributeName: NSFont.systemFont(ofSize: 0)]
> let nameString = NSAttributedString(string: field.name, attributes: attributes)
> let bodyString = NSAttributedString(string: field.body, attributes: attributes)
> for (string, column) in [(nameString, nameColumn), (bodyString, bodyColumn)] {
> let frame = NSRect(x: 0.0, y: 0.0, width: column.width, height: .greatestFiniteMagnitude)
> let view = NSTextView(frame: frame)
> view.textStorage?.setAttributedString(string)
> view.isHorizontallyResizable = false
> view.sizeToFit()
> height = max(height, view.frame.size.height /*+ 20*/)
> }
>
> return height
> }
But it only establishes the row heights once, at start but never after any resizes (column or whole-table). It still is short on some long lines. (Is it because I use word-wrap, instead of by character, for that column?) Also, I hard-coded the font to match what the table has. Is there any way to read what the cell template has? (“NSTableView.view(something)” can generate a view for a given row and column, but Apple specifically barred it (with an assert/exception) during this method.)
—
Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden