在自定义NSCollectionViewLayout子类上未调用invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:)

时间:2018-09-23 17:46:36

标签: macos appkit nscollectionview nscollectionviewitem nscollectionviewlayout

Link to the relevant sample project

说明

我正在尝试创建一个自定义NSCollectionViewLayout子类,该子类使用“自动布局”来确定其项目的大小。此布局从上到下放置项目,所有项目共享相同的宽度,但每个项目的高度由其内容决定。可以将其视为macOS的UITableView布局。

假设

初始布局属性是在布局的prepare()方法中计算的,并通过layoutAttributesForElements(in:)提供给集合视图。集合视图使用这些属性来确定需要显示哪些项目。这些项目由集合视图的委托提供,并且调用每个项目的apply(_:)方法以设置其视图属性。

然后,集合视图将调用项目的preferredLayoutAttributesFitting(_:)方法以计算其内容的合适大小。然后,返回的属性将传递到集合视图布局的shouldInvalidateLayout(forPreferredLayoutAttributes:withOriginalAttributes:)方法中,在该方法中,布局将确定是否需要针对新属性进行调整,并将该布尔决策返回给集合视图。

如果布局决定需要使其无效,则收集视图将调用invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:)从布局中获取有关如何更新自身的特定信息。当集合视图随后调用invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:)时,布局可以应用这些更改。

然后重复此过程,直到每个布局项目的shouldInvalidateLayout(forPreferredLayoutAttributes:withOriginalAttributes:)返回false-提示收集视图以在屏幕上显示项目。

前提

ListLayout的{​​{1}}子类能够为每个NSCollectionViewLayout创建一个初始的布局属性集,其初始高度为NSCollectionViewItem点。我们期望使用“自动布局”来确定每个项目的实际高度,因此该初始值应该无关紧要。

然后,布局可以通过10提供这些初始属性的正确集合。

layoutAttributesForElements(in:)的{​​{1}}子类包含一个TextFieldItem实例,该实例被设置为其NSCollectionViewItemNSTextField属性。此视图的view属性设置为false,并具有所需的垂直内容压缩优先级。覆盖项的textField方法可将文本字段的translatesAutoresizingMaskIntoConstraints设置为给定属性提供的宽度。覆盖该项的apply(_:)方法可将首选属性的高度设置为等于文本字段的preferredMaxLayoutWidth属性。

向集合视图提供了preferredLayoutAttributesFitting(_:)实例,其中填充了多行文本。

预计每个intrinsicContentSize将在其TextFieldItem方法之后调用其TextFieldItem方法,然后调用布局的preferredLayoutAttributesFitting(_:)和{{1} }方法。

但是,游乐场运行时,apply(_:)shouldInvalidateLayout(forPreferredLayoutAttributes:withOriginalAttributes:)invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:)都不会被调用。结果,每个项目的高度都保持在初始的“估计”高度。

Each text field should display three lines of text, but only the top of the first line is visible.

问题

关于preferredLayoutAttributesFitting(_:)和“自动版式”,我肯定缺少一些东西,但是我在文档中没有发现任何指示。

我尝试在集合视图的生命周期的各个不同点手动调用这些方法,但是没有任何方法能够正确触发布局以调整其归类属性。

是否需要在集合视图,其布局或指示shouldInvalidateLayout(forPreferredLayoutAttributes:withOriginalAttributes:)的项目上设置属性? invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:)NSCollectionViewLayout的子类仅支持自动版式吗?还是我误解了preferredLayoutAttributesFitting(_:)实例的生命周期?

1 个答案:

答案 0 :(得分:0)

我有同样的问题,这是我的解决方案,它可以完美运行。 将下面的代码添加到UICollectionViewCell的子类中。

override func awakeFromNib() {

    super.awakeFromNib()

    self.contentView.translatesAutoresizingMaskIntoConstraints = false

    let leftConstraint = contentView.leftAnchor.constraint(equalTo: leftAnchor)
    let rightConstraint = contentView.rightAnchor.constraint(equalTo: rightAnchor)
    let topConstraint = contentView.topAnchor.constraint(equalTo: topAnchor)
    let bottomConstraint = contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
    NSLayoutConstraint.activate([leftConstraint, rightConstraint, topConstraint, bottomConstraint])
}