Macos 10.11 NSCollectionView-动态确定单元格大小

Macos 10.11 NSCollectionView-动态确定单元格大小,macos,cocoa,autolayout,nscollectionview,nscollectionviewitem,Macos,Cocoa,Autolayout,Nscollectionview,Nscollectionviewitem,建议可以根据每个项目调整集合视图项目的大小: 可以为CollectionView的所有项全局确定项大小(通过设置NSCollectionViewFlowLayout的“itemSize”属性),也可以在不同的项之间改变项大小(通过在CollectionView的委托上实现-CollectionView:layout:SizeFormiteIndeXPath:) 在我的例子中,我的CollectionViewItem由一个标签组成,其中包含一个长度不同的字符串。我使用NSCollectionVie

建议可以根据每个项目调整集合视图项目的大小:

可以为CollectionView的所有项全局确定项大小(通过设置NSCollectionViewFlowLayout的“itemSize”属性),也可以在不同的项之间改变项大小(通过在CollectionView的委托上实现-CollectionView:layout:SizeFormiteIndeXPath:)

在我的例子中,我的CollectionViewItem由一个标签组成,其中包含一个长度不同的字符串。我使用NSCollectionView显示字符串数组,因为NSStackView不支持数组绑定,也不流向新行。字符串数组通过数组控制器绑定到NSCollectionView的内容

“我的项目”的nib文件已正确设置,根视图和标签的内容拥抱和内容压缩优先级均为1000,边缘通过自动布局对齐

现在,NSCollectionViewLayout的委托方法具有以下签名:

func collectionView(collectionView: NSCollectionView, 
                    layout collectionViewLayout: NSCollectionViewLayout, 
                    sizeForItemAtIndexPath indexPath: NSIndexPath) -> NSSize
我现在的想法是抓取项目本身,在其上运行布局传递,然后返回新的项目大小

let item = collectionView.itemAtIndexPath(indexPath)!
item.view.layout()
return item.view.bounds.size
这种方法的问题是itemAtIndexPath返回nil。如果在nil情况下返回默认大小,则该默认大小将用于所有单元格


如何设置NSCollectionView以尊重项目的自动布局约束,并为每个单元格动态使用计算的大小?

我回答了一个重复的问题,但这可能是它应该指向的问题,因为它比较旧

尤尔的评论是正确的——这些物品不存在<调用的代码>sizeForItemAt是一个集合,它要求代理为该数据项指定任何特定的大小,并使用该数据项帮助创建其最终视图控制器,
NSCollectionViewItem
。因此,当您要求集合在其用于帮助获取项目的方法中获取项目时,您将创建一个循环

我们的问题是,我们希望根据数据的外观来调整大小:具有适当格式的文本标签的长度,而不仅仅是字符串长度。所以我们遇到了鸡和蛋的问题

我找到的唯一解决方案可能会更漂亮,如下所示:

把…准备好
  • 子类
    NSCollectionViewItem
    ,并确保集合视图具有返回正确子类项的数据源
  • 完全使用XIB中的约束
  • 您的子类应该有一个加载到要表示的数据对象中的方法——当然也包括您的数据源协议方法
  • 在第一次调用
    sizeForItemAt
    之前的某个时间点,或者在第一次调用开始时(如果那时您还没有),手动创建
    NSCollectionViewItem
    子类的实例,并使用NSNib的
    实例化(with owner:topLevelObjects:)
    以您的子类为所有者实例化其XIB。将该引用存储为一种“大小调整模板”,因此只需执行一次。代表是我最容易的位置
^注意:我的第一个方法是尝试通过集合的
makeItemWithIdentifier
,但它更脆弱,因为它要求集合在创建大小调整模板时拥有项目。在初始
sizeForItemAt
期间也无法执行此操作(在重新加载期间访问/制作项目)。我担心,因为它是用集合制作的,它可能会被重复使用,下面的方法不起作用,或者开始编辑可见项。YMMV

SizeForestMat中
  • 直接从数据源获取要表示的数据对象。让您的大小调整模板对象用我前面提到的方法表示该数据对象
  • 访问尺寸模板的
    视图。FittingSize
    ,可以为项目指定约束/优先级的最小尺寸,并返回该值
砰!我没有做过压力测试或其他任何事情,但没有任何问题,也没有做布局传递或其他任何事情,只是调用
FittingSize
。我还没有在网上看到这一点,所以我想写下完整的解释

我是在Xamarin.Mac中这样做的,所以我的代码不会是1:1,我不想写乱七八糟的swift,把事情搞砸


TLDR:手动实例化NSCollectionViewItem子类及其要存储的xib,该子类不为集合所有。在sizeForItem期间,填充存储为尺寸参考的项目,并返回集合项目视图的
FittingSize

我的快速想法是不使用
itemAtIndexPath
获取项目。取而代之的是从模型中获取内容并计算高度。该项目还不在collectionview中,这就是为什么返回
nil
。集合视图在将其添加到视图之前会询问您大小。这是一个很好的解释,但您如何处理强制自动布局约束的实际问题?我对此也很感兴趣,目前还没有正确的答案。但是我认为自动布局总是自上而下的,框架是由集合视图独立于任何AL设置的。所有拥抱等只影响项目框架内的视图。项目框架本身仅由CollectionViewLayout(或您正在使用的委托方法)定义。也许一个人可以只分配一个自己的额外项目用于调整大小,应用模型(设置表示的对象),获取大小并返回它?