10.11 NSCollectionView - determining cell size dynamically

爱⌒轻易说出口 提交于 2019-12-03 02:53:07

There's a duplicate of this question that I answered but this is probably the one it should be directed to since it's older.

Juul's comment is correct- the items do not exist. sizeForItemAt being called is the collection asking the delegate for any specific sizing for that data entry with which it will use to help create its eventual view controller, NSCollectionViewItem. So you create a loop when you ask the collection to get you an item in the method that it uses to help get an item.

The problem we have is that we want sizing based on the appearance of that data: the length of a text label with proper formatting, not just, say, the string length. So we hit a chicken and egg problem.

The only solution I've come to, which could be prettier, is the following:

Prep

  • Subclass NSCollectionViewItem and ensure your collection view has a data source that returns the proper subclassed item.
  • Use constraints in your XIB, completely.
  • Your subclass should have a method that loads in the data object to be represented- both for this and of course your data source protocol methods.
  • At some point prior to the first sizeForItemAt call, or at the beginning of the first one if you hadn't by then, manually create an instance of your NSCollectionViewItem subclass, and use NSNib's instantiate(withOwner:topLevelObjects:) to instantiate its XIB with your subclass as an owner. Store that reference as a sort of "sizing template," so you only need to do it once. Delegate was easiest spot for me.

^Note: my first route was to attempt this through the collection's makeItemWithIdentifier, but it was more brittle as it required the collection to have items at the time of creating the sizing template. It also could not be done during an initial sizeForItemAt (accessing/making items during a reload crashes). And I was worried that because it was made with the collection it may get reused down the line and the methods below don't work or start editing visible items. YMMV.

In sizeForItemAt

  • Directly get the data object being represented from the datasource. Have your sizing template object represent that data object with the method I mentioned earlier.
  • Access the sizing template's View.FittingSize, the smallest size an item can be given its constraints/priorities, and return that.

Bam! Hasn't been stress tested or anything but no problems on my end, and its not doing a layout pass or anything, just calling FittingSize. I haven't seen this articulated anywhere online yet, so I wanted to write out the full explanation.

I did this in Xamarin.Mac, so my code won't be 1:1 and I don't want to write garbled swift and mess anything up.

TLDR: manually instantiate a NSCollectionViewItem subclass and its xib that you will store, unowned by the collection. During sizeForItem populate that item you store as a sizing reference, and return the FittingSize of the collection item's view.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!