Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
607 views
in Technique[技术] by (71.8m points)

cocoa - NSCollectionView with Dynamic Width Items Using Auto Layout

I'm building an NSCollectionView that scrolls horizontally with items that look something like this:

The Goal

I have my NSCollectionView item defined in a .xib with auto layout constraints. The width of the item is defined by the width of the label plus the width of the count label (and its surrounding pill). All this is encapsulated by an NSView called "Box."

enter image description here

Here are the constraints for Box:

enter image description here

I have my datasource hooked up and everything seems fine except I can't get the width of the item to change based on the sizes of the views inside it.

From what I've read, I can't rely solely on auto layout to define the size here (I hope I'm wrong about that) much like I would with a dynamic height in an NSTableView. So I'm trying to calculate the size with the sizeForItemAt delegate method from NSCollectionViewDelegateFlowLayout:

func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
  let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "PhaseItem"), for: indexPath) as! PhaseItem
    
  return item.box.fittingSize
}

When I print the fittingSize to the console, it looks right. But I'm getting a Unable to simultaneously satisfy constraints crash related to the size of Box (it has a subclass of RoundedWrap):

"<NSLayoutConstraint:0x6000033c3890 H:|-(11)-[NSTextField:0x7ff6abf6e9f0]   (active, names: '|':Avid.RoundedWrap:0x7ff6abf74840 )>",
"<NSLayoutConstraint:0x6000033c6300 H:[NSTextField:0x7ff6abf6e9f0]-(7)-[Avid.BadgeView:0x7ff6abf6f120]   (active)>",
"<NSLayoutConstraint:0x6000033c5400 H:[Avid.BadgeView:0x7ff6abf6f120]-(9)-|   (active, names: '|':Avid.RoundedWrap:0x7ff6abf74840 )>",
"<NSLayoutConstraint:0x6000033c39d0 H:|-(8)-[NSTextField:0x7ff6abf6f360]   (active, names: '|':Avid.BadgeView:0x7ff6abf6f120 )>",
"<NSLayoutConstraint:0x6000033c2760 H:[NSTextField:0x7ff6abf6f360]-(8)-|   (active, names: '|':Avid.BadgeView:0x7ff6abf6f120 )>",
"<NSLayoutConstraint:0x6000033c3a20 H:|-(0)-[Avid.RoundedWrap:0x7ff6abf74840]   (active, names: '|':NSView:0x7ff6abf74a80 )>",
"<NSLayoutConstraint:0x6000033c3b60 H:[Avid.RoundedWrap:0x7ff6abf74840]-(0)-|   (active, names: '|':NSView:0x7ff6abf74a80 )>",
"<NSAutoresizingMaskLayoutConstraint:0x6000033140f0 h=--& v=--& NSView:0x7ff6abf74a80.width == 0   (active)>"

The crash goes away if I remove the constraint that pins the trailing edge of the Box to the containing view, but then my NSCollectionView items don't appear at all.

Is there an easier way to do all this? How can I use auto layout to set the dynamic width of my NSCollectionViewItems?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

It looks like I was on the right track. I just needed to add:

item.view.layoutSubtreeIfNeeded()

Like this

func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
  ///...
  item.view.layoutSubtreeIfNeeded()
  return item
}

In order for the item size to be accurate.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...