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

Ric*_*hiy 8 ios autolayout uicollectionview swift uicollectionviewflowlayout

环境:
UICollectionView看起来像UITableView的
自定义UICollectionViewFlowLayout子类来定义frame的的DecorationView
启用自调整大小细胞

预期行为:
A DecorationView应该作为背景放置在每个部分UICollectionView

预期的行为

观察到的行为:
DecorationView崩溃到任意尺寸:

观察到的行为

似乎UICollectionView试图计算自动大小DecorationView.如果我禁用Self-Sizing单元格,则装饰视图将精确放置在预期位置.

有没有办法禁用Self-Sizing DecorationView

在我的UICollectionViewFlowLayout子类中,我只需要截取该部分中的第一个和最后一个单元格并拉伸背景以填充它们下面的空间.问题是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
}
Run Code Online (Sandbox Code Playgroud)

jam*_*esk 5

在单元格的框架自行调整大小后,装饰视图的框架可能不会更新(即无效)。结果是每个装饰视图的宽度保持其默认大小。

尝试实现此函数,每次该部分中的项目的布局无效时,该函数都会使每个部分的装饰视图的布局无效:

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