在 UICollectionViewFlowLayout 中启用 AutoSizing 单元格时,DecorationView 会调整大小

DecorationView gets resized when AutoSizing cells are enabled in UICollectionViewFlowLayout

环境:
UICollectionView 看起来像 UITableView
自定义 UICollectionViewFlowLayout 子类来定义 DecorationView
frame 已启用自调整单元格

预期行为:
DecorationView 应作为 UICollectionView

每个部分的背景

观察到的行为:
DecorationView 折叠成任意大小:

似乎 UICollectionView 试图计算 DecorationView 的自动大小。如果我禁用自调整单元格,则装饰视图将准确放置在预期位置。

有什么方法可以为 DecorationView 禁用自我调整大小?

在我的 UICollectionViewFlowLayout 子类中,我简单地获取该部分中的第一个和最后一个单元格并拉伸背景以填充它们下面的 space。问题是 UICollectionView 不遵守那里计算的大小:

override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    guard let collectionView = collectionView else {
      return nil
    }

    let section = indexPath.section
    let attrs = UICollectionViewLayoutAttributes(forDecorationViewOfKind: backgroundViewClass.reuseIdentifier(),
                                                 with: indexPath)
    let numberOfItems = collectionView.numberOfItems(inSection: section)
    let lastIndex = numberOfItems - 1

    guard let firstItemAttributes = layoutAttributesForItem(at: IndexPath(indexes: [section, 0])),
      let lastItemAttributes = layoutAttributesForItem(at: IndexPath(indexes: [section, lastIndex])) else {
        return nil
    }

    let startFrame = firstItemAttributes.frame
    let endFrame = lastItemAttributes.frame

    let origin = startFrame.origin
    let size = CGSize(width: startFrame.width,
                      height: -startFrame.minY + endFrame.maxY)

    let frame = CGRect(origin: origin, size: size)
    attrs.frame = frame
    attrs.zIndex = -1

    return attrs
}

在单元格的框架 self-sized 之后,装饰视图的框架可能没有更新(即无效)。结果是每个装饰视图的宽度都保持默认大小。

尝试实现这个功能,每次该部分中的项目布局无效时,它应该使每个部分的装饰视图布局无效:

override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext) {
    let invalidatedSections = context.invalidatedItemIndexPaths?.map { [=10=].section } ?? []
    let decorationIndexPaths = invalidatedSections.map { IndexPath(item: 0, section: [=10=]) }
    context.invalidateDecorationElements(ofKind: backgroundViewClass.reuseIdentifier(), at: decorationIndexPaths)
    super.invalidateLayout(with: context)
}