10.11 NSCollectionView - 动态确定单元大小

Eta*_*tan 10 macos cocoa nscollectionview nscollectionviewitem autolayout

适用于OS X v10.11的AppKit发行说明建议可以基于每个项目调整集合视图项目的大小:

可以为所有CollectionView的项目全局确定项目大小(通过设置NSCollectionViewFlowLayout的"itemSize"属性),也可以从一个项目到下一个项目(通过在CollectionView的委托上实现-collectionView:layout:sizeForItemAtIndexPath:)进行更改.

在我的例子中,我的CollectionViewItem包含一个包含不同长度字符串的标签.我正在使用NSCollectionView来显示字符串数组,因为NSStackViews不支持数组绑定,并且不会流向新行.字符串数组通过数组控制器绑定到NSCollectionView的内容.

我的项目的nib文件已正确设置,根视图和标签都具有内容拥抱内容压缩阻力优先级1000,并且边缘通过AutoLayout对齐.

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

func collectionView(collectionView: NSCollectionView, 
                    layout collectionViewLayout: NSCollectionViewLayout, 
                    sizeForItemAtIndexPath indexPath: NSIndexPath) -> NSSize
Run Code Online (Sandbox Code Playgroud)

我现在的想法是抓住项目本身,对其进行布局传递,然后返回新项目大小.

let item = collectionView.itemAtIndexPath(indexPath)!
item.view.layout()
return item.view.bounds.size
Run Code Online (Sandbox Code Playgroud)

这种方法的问题是itemAtIndexPath返回nil.如果我以零值返回默认大小,则默认大小将用于所有单元格.

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

Nic*_*pag 4

我回答了这个问题的重复项,但这可能是应该针对的问题,因为它较旧。

Juul 的评论是正确的 - 这些项目不存在。 sizeForItemAt被调用的是请求委托提供该数据条目的任何特定大小的集合,它将用于帮助创建其最终的视图控制器NSCollectionViewItem。因此,当您要求集合在它用于帮助获取项目的方法中获取项目时,您会创建一个循环。

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

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

准备

  • 子类化NSCollectionViewItem并确保您的集合视图具有返回正确子类化项目的数据源。
  • 完全使用 XIB 中的约束。
  • 您的子类应该有一个加载要表示的数据对象的方法 - 当然还有您的数据源协议方法。
  • 在第一次调用之前的某个时刻sizeForItemAt,或者在第一次调用开始时(如果您当时还没有),手动创建NSCollectionViewItem子类的实例,并使用 NSNibinstantiate(withOwner:topLevelObjects:)以您的子类作为所有者来实例化其 XIB。将该参考存储为一种“调整模板”,因此您只需执行一次。代表对我来说是最容易的地方。

^注意:我的第一个途径是通过集合的 尝试此操作makeItemWithIdentifier,但它更脆弱,因为它要求集合在创建大小调整模板时具有项目。它也无法在初始期间完成sizeForItemAt(在重新加载崩溃期间访问/制作项目)。我担心因为它是用集合制作的,所以它可能会被重复使用,并且下面的方法不起作用或开始编辑可见项目。YMMV。

sizeForItemAt

  • 直接从数据源获取所表示的数据对象。让您的大小调整模板对象使用我之前提到的方法来表示该数据对象。
  • 访问尺寸模板的View.FittingSize,可以给项目指定其约束/优先级的最小尺寸,然后返回该尺寸。

嘭!没有经过压力测试或任何东西,但我这边没有任何问题,并且它没有进行布局传递或任何东西,只是调用FittingSize. 我还没有在网上的任何地方看到这一点,所以我想写出完整的解释。

我在 Xamarin.Mac 中执行此操作,因此我的代码不会是 1:1,并且我不想快速编写乱码并弄乱任何内容。

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