【问题标题】:invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:) isn't called on a custom NSCollectionViewLayout subclass在自定义 NSCollectionViewLayout 子类上未调用 invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:)
【发布时间】:2019-02-27 08:08:56
【问题描述】:

Link to the relevant sample project

说明

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

假设

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

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

如果布局决定它需要失效,那么集合视图将调用invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:) 从布局中获取具体信息,以了解它应该如何自我更新。当集合视图随后调用invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:) 时,布局可以应用这些更改。

然后重复此过程,直到 shouldInvalidateLayout(forPreferredLayoutAttributes:withOriginalAttributes:) 为每个布局项返回 false — 提示集合视图在屏幕上显示这些项。

前提

NSCollectionViewLayoutListLayout 子类能够为每个NSCollectionViewItem 创建一组初始布局属性,“估计”初始高度为10 点。我们希望使用 Auto Layout 来确定每个项目的实际高度,所以这个初始值应该无关紧要。

然后布局能够通过layoutAttributesForElements(in:) 提供正确的初始属性集。

NSCollectionViewItemTextFieldItem 子类包含一个 NSTextField 实例,该实例设置为其 viewtextField 属性。此视图将其translatesAutoresizingMaskIntoConstraints 属性设置为false,并具有所需的垂直内容压缩阻力优先级。该项目的apply(_:) 方法被覆盖,以将文本字段的preferredMaxLayoutWidth 设置为给定属性提供的宽度。项目的 preferredLayoutAttributesFitting(_:) 方法被覆盖以将首选属性的高度设置为等于文本字段的 intrinsicContentSize 属性。

集合视图提供了TextFieldItem 的实例,其中填充了多行文本。

预计每个TextFieldItem 将在其apply(_:) 方法之后调用其preferredLayoutAttributesFitting(_:) 方法,然后调用布局的shouldInvalidateLayout(forPreferredLayoutAttributes:withOriginalAttributes:)invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:) 方法。

但是,在运行 Playground 时,不会调用 preferredLayoutAttributesFitting(_:)shouldInvalidateLayout(forPreferredLayoutAttributes:withOriginalAttributes:)invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:)。因此,每个项目的高度都保持在最初的“估计”高度。

问题

NSCollectionViewLayout 和自动布局一定是我遗漏了一些东西,但我在文档中没有找到任何表明这一点的内容。

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

是否需要在集合视图、其布局或项目上设置一个属性来指示应该调用preferredLayoutAttributesFitting(_:)?自动布局是否仅支持 NSCollectionViewFlowLayoutNSCollectionViewGridLayout 的子类?还是我误解了NSCollectionViewLayout 实例的生命周期?

【问题讨论】:

  • 如果您在反馈助手中提交报告,请在此处发布 FB #,我会尝试放大信号。

标签: macos appkit nscollectionview nscollectionviewitem nscollectionviewlayout


【解决方案1】:

我有同样的问题,这是我的解决方案,效果很好。 将以下代码添加到 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])
}

【讨论】:

  • 感谢您的回答,但我是为 macOS 而不是 iOS 写的。 UICollectionViewCellNSCollectionViewItem 的行为有点不同。
猜你喜欢
  • 2019-02-23
  • 2016-06-23
  • 1970-01-01
  • 2021-03-19
  • 2023-03-30
  • 1970-01-01
  • 2014-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多