> On Mar 18, 2017, at 3:21 AM, Quincey Morris 
> <quinceymor...@rivergatesoftware.com> wrote:
> 
> On Mar 17, 2017, at 23:18 , Daryle Walker <dary...@mac.com 
> <mailto:dary...@mac.com>> wrote:
>> 
>> The table isn’t using the new values, though.
> 
> There’s no direct relationship linking the intrinsic size to the row height. 
> That’s kinda the point. Nothing is going to happen automatically. You have to 
> detect when the row height might change (e.g. when the text is edited), and 
> run autolayout on a prototype cell. Autolayout uses the intrinsic height to 
> resize the cell view. That gives you the height, and then you must manually 
> tell the table that the height for the row has changed.

Let’s restart with the code based on Jeremy Hughes’ post:

> class WrappingTextField: NSTextField {
> 
>     override var intrinsicContentSize: NSSize {
>         guard let cell = self.cell, cell.wraps else { return 
> super.intrinsicContentSize }
> 
>         self.validateEditing()
>         return cell.cellSize(forBounds: NSRect(x: 0, y: 0, width: 
> self.bounds.width, height: .greatestFiniteMagnitude))
>     }
> 
>     override func textDidChange(_ notification: Notification) {
>         super.textDidChange(notification)
>         self.invalidateIntrinsicContentSize()
>     }
> 
> }

This clip uses the field’s “bounds,” but based on code I saw on StackOverflow 
(<http://stackoverflow.com/a/10463761/1010226>), I changed it to the “frame” 
instead. I think the latter is what you need when sizing a view relative to its 
super-view.

Previous versions of my code had a huge KVO setup to watch for string changes 
and caching the results. Looking back, it was too much on the wrong side of 
“work smarter, not harder.” The text fields derived their value from my model, 
but as far as the surrounding table-view is concerned, the text-fields are the 
only source of “truth” that matters! That means sourcing the table-view update 
flag from these text fields. I can modify the (second) method above, put how to 
I figure out what row needs to be updated. Hint: the table-view surrounds the 
text-fields. The table view surrounds a list of row views, which surround a 
list of cell views (which are generated by the table-column markers, which 
aren’t views themselves). Work backwards from the field to get the row and 
table. But, unlike columns, the table does not hold a convenient array of rows.

>     override var intrinsicContentSize: NSSize {
>         guard let cell = self.cell, cell.wraps else { return 
> super.intrinsicContentSize }
> 
>         validateEditing()
>         return cell.cellSize(forBounds: NSRect(x: 0, y: 0, width: 
> frame.width, height: .greatestFiniteMagnitude))
>     }
> 
>     override func textDidChange(_ notification: Notification) {
>         super.textDidChange(notification)
>         self.invalidateIntrinsicContentSize()
> 
>         if let rowView = superview?.superview as? NSTableRowView, let 
> tableView = rowView.superview as? NSTableView {
>             tableView.enumerateAvailableRowViews { currentRowView, 
> currentRowIndex in
>                 if rowView === currentRowView {
>                     tableView.noteHeightOfRows(withIndexesChanged: 
> IndexSet(integer: currentRowIndex))
>                 }
>             }
>         }
>     }

I don’t look for the immediately-surrounding NSTableCellVIew because the 
surrounding view may be of a different class, and that fact doesn’t matter as 
long as I can get the row-view surrounding the cell views. Now, I do make a 
table-view delegate to compute the new row height. Before, I had problems 
generating a cell to work on. Apple explicitly bars two of the generating 
methods from working in the delegate call. But I can use the third one to make 
a prototype cell. I searched for row-adjusting code on GitHub, and adapted the 
last full method on 
<https://github.com/konstantinpavlikhin/KSPAutomaticHeightCalculationTableCellView/blob/master/Sources/KSPAutomaticHeightCalculationTableCellView.m>
 to help:

> extension MessageHeaderViewController: NSTableViewDelegate {
> 
>     func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat 
> {
>         var height = tableView.rowHeight
>         guard self.headerTable === tableView, let field = 
> self.headerArray[row] as? RawHeaderField else { return height }
> 
>         for (columnId, value) in [(Names.nameColumn, field.name), 
> (Names.bodyColumn, field.body)] {
>             guard let prototypeCell = tableView.make(withIdentifier: 
> columnId, owner: self) as? NSTableCellView else {
>                 continue
>             }
> 
>             let column = 
> tableView.tableColumns[tableView.column(withIdentifier: columnId)]
>             prototypeCell.textField?.stringValue = value
>             prototypeCell.widthAnchor.constraint(equalToConstant: 
> column.width).isActive = true
>             prototypeCell.layoutSubtreeIfNeeded()
>             height = max(height, prototypeCell.fittingSize.height)
>         }
>         return height
>     }
> 
>     func tableViewColumnDidResize(_ notification: Notification) {
>         guard self.headerTable === (notification.object as? NSTableView) else 
> { return }
> 
>         self.headerTable.noteHeightOfRows(withIndexesChanged: 
> IndexSet(integersIn: 0 ..< self.headerTable.numberOfRows))
>     }
> 
> }

I used a new (to me) way of expressing the width constraint. Hope this’ll help 
with someone else searching for this.

— 
Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com 

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to