• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Auto-sized table cells, for macOS
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


  • Follow-Ups:
    • Re: Auto-sized table cells, for macOS
      • From: Quincey Morris <email@hidden>
References: 
 >Auto-sized table cells, for macOS (From: Daryle Walker <email@hidden>)
 >Re: Auto-sized table cells, for macOS (From: Quincey Morris <email@hidden>)

  • Prev by Date: Re: Menu Item Shortcuts Without Menu Items?
  • Next by Date: Re: NSTableView column sizes
  • Previous by thread: Re: Auto-sized table cells, for macOS
  • Next by thread: Re: Auto-sized table cells, for macOS
  • Index(es):
    • Date
    • Thread